{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Title: #Minimum Cost to Make at Least One Valid Path in a Grid"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Difficulty: #Hard"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Category Title: #Algorithms"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Tag Slug: #breadth-first-search #graph #array #matrix #shortest-path #heap-priority-queue"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Name Translated: #广度优先搜索 #图 #数组 #矩阵 #最短路 #堆（优先队列）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Solution Name: minCost"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Translated Title: #使网格图至少有一条有效路径的最小代价"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Translated Content:\n",
    "<p>给你一个 m x n 的网格图&nbsp;<code>grid</code>&nbsp;。&nbsp;<code>grid</code>&nbsp;中每个格子都有一个数字，对应着从该格子出发下一步走的方向。&nbsp;<code>grid[i][j]</code>&nbsp;中的数字可能为以下几种情况：</p>\n",
    "\n",
    "<ul>\n",
    "\t<li><strong>1</strong>&nbsp;，下一步往右走，也就是你会从 <code>grid[i][j]</code>&nbsp;走到 <code>grid[i][j + 1]</code></li>\n",
    "\t<li><strong>2</strong>&nbsp;，下一步往左走，也就是你会从 <code>grid[i][j]</code>&nbsp;走到 <code>grid[i][j - 1]</code></li>\n",
    "\t<li><strong>3</strong>&nbsp;，下一步往下走，也就是你会从 <code>grid[i][j]</code>&nbsp;走到 <code>grid[i + 1][j]</code></li>\n",
    "\t<li><strong>4</strong>&nbsp;，下一步往上走，也就是你会从 <code>grid[i][j]</code>&nbsp;走到 <code>grid[i - 1][j]</code></li>\n",
    "</ul>\n",
    "\n",
    "<p>注意网格图中可能会有&nbsp;<strong>无效数字</strong>&nbsp;，因为它们可能指向&nbsp;<code>grid</code>&nbsp;以外的区域。</p>\n",
    "\n",
    "<p>一开始，你会从最左上角的格子&nbsp;<code>(0,0)</code>&nbsp;出发。我们定义一条&nbsp;<strong>有效路径</strong>&nbsp;为从格子&nbsp;<code>(0,0)</code>&nbsp;出发，每一步都顺着数字对应方向走，最终在最右下角的格子&nbsp;<code>(m - 1, n - 1)</code>&nbsp;结束的路径。有效路径&nbsp;<strong>不需要是最短路径</strong>&nbsp;。</p>\n",
    "\n",
    "<p>你可以花费&nbsp;<code>cost = 1</code>&nbsp;的代价修改一个格子中的数字，但每个格子中的数字&nbsp;<strong>只能修改一次</strong>&nbsp;。</p>\n",
    "\n",
    "<p>请你返回让网格图至少有一条有效路径的最小代价。</p>\n",
    "\n",
    "<p>&nbsp;</p>\n",
    "\n",
    "<p><strong>示例 1：</strong></p>\n",
    "\n",
    "<p><img alt=\"\" src=\"https://assets.leetcode-cn.com/aliyun-lc-upload/uploads/2020/02/29/grid1.png\" style=\"height: 528px; width: 542px;\"></p>\n",
    "\n",
    "<pre><strong>输入：</strong>grid = [[1,1,1,1],[2,2,2,2],[1,1,1,1],[2,2,2,2]]\n",
    "<strong>输出：</strong>3\n",
    "<strong>解释：</strong>你将从点 (0, 0) 出发。\n",
    "到达 (3, 3) 的路径为： (0, 0) --&gt; (0, 1) --&gt; (0, 2) --&gt; (0, 3) 花费代价 cost = 1 使方向向下 --&gt; (1, 3) --&gt; (1, 2) --&gt; (1, 1) --&gt; (1, 0) 花费代价 cost = 1 使方向向下 --&gt; (2, 0) --&gt; (2, 1) --&gt; (2, 2) --&gt; (2, 3) 花费代价 cost = 1 使方向向下 --&gt; (3, 3)\n",
    "总花费为 cost = 3.\n",
    "</pre>\n",
    "\n",
    "<p><strong>示例 2：</strong></p>\n",
    "\n",
    "<p><img alt=\"\" src=\"https://assets.leetcode-cn.com/aliyun-lc-upload/uploads/2020/02/29/grid2.png\" style=\"height: 408px; width: 419px;\"></p>\n",
    "\n",
    "<pre><strong>输入：</strong>grid = [[1,1,3],[3,2,2],[1,1,4]]\n",
    "<strong>输出：</strong>0\n",
    "<strong>解释：</strong>不修改任何数字你就可以从 (0, 0) 到达 (2, 2) 。\n",
    "</pre>\n",
    "\n",
    "<p><strong>示例 3：</strong></p>\n",
    "\n",
    "<p><img alt=\"\" src=\"https://assets.leetcode-cn.com/aliyun-lc-upload/uploads/2020/02/29/grid3.png\" style=\"height: 302px; width: 314px;\"></p>\n",
    "\n",
    "<pre><strong>输入：</strong>grid = [[1,2],[4,3]]\n",
    "<strong>输出：</strong>1\n",
    "</pre>\n",
    "\n",
    "<p><strong>示例 4：</strong></p>\n",
    "\n",
    "<pre><strong>输入：</strong>grid = [[2,2,2],[2,2,2]]\n",
    "<strong>输出：</strong>3\n",
    "</pre>\n",
    "\n",
    "<p><strong>示例 5：</strong></p>\n",
    "\n",
    "<pre><strong>输入：</strong>grid = [[4]]\n",
    "<strong>输出：</strong>0\n",
    "</pre>\n",
    "\n",
    "<p>&nbsp;</p>\n",
    "\n",
    "<p><strong>提示：</strong></p>\n",
    "\n",
    "<ul>\n",
    "\t<li><code>m == grid.length</code></li>\n",
    "\t<li><code>n == grid[i].length</code></li>\n",
    "\t<li><code>1 &lt;= m, n &lt;= 100</code></li>\n",
    "</ul>\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Description: [minimum-cost-to-make-at-least-one-valid-path-in-a-grid](https://leetcode.cn/problems/minimum-cost-to-make-at-least-one-valid-path-in-a-grid/description/)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Solutions: [minimum-cost-to-make-at-least-one-valid-path-in-a-grid](https://leetcode.cn/problems/minimum-cost-to-make-at-least-one-valid-path-in-a-grid/solutions/)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "test_cases = ['[[1,1,1,1],[2,2,2,2],[1,1,1,1],[2,2,2,2]]', '[[1,1,3],[3,2,2],[1,1,4]]', '[[1,2],[4,3]]']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, startPos: List[int], homePos: List[int], rowCosts: List[int], colCosts: List[int]) -> int:\n",
    "        x, y = startPos\n",
    "        X, Y = homePos\n",
    "        ans = sum(rowCosts[x+1:X+1]) if x < X else sum(rowCosts[X:x])\n",
    "        ans += sum(colCosts[y+1:Y+1]) if y < Y else sum(colCosts[Y:y])\n",
    "        return ans"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, startPos: List[int], homePos: List[int], rowCosts: List[int], colCosts: List[int]) -> int:\n",
    "        m = len(rowCosts)\n",
    "        n = len(colCosts)\n",
    "        sx,sy = startPos\n",
    "        tx,ty = homePos\n",
    "        if sx==tx and sy==ty:\n",
    "            return 0\n",
    "        smallx = sx if sx<tx else tx\n",
    "        largex = tx if sx<tx else sx\n",
    "        smally = sy if sy<ty else ty\n",
    "        largey = ty if sy<ty else sy\n",
    "        res = 0\n",
    "        if largex!=smallx:\n",
    "            for i in range(smallx+1, largex):\n",
    "                res += rowCosts[i]\n",
    "            res += rowCosts[tx]\n",
    "        if largey!=smally:\n",
    "            for i in range(smally+1, largey):\n",
    "                res += colCosts[i]\n",
    "            res += colCosts[ty]\n",
    "        return res"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution(object):\n",
    "    def minCost(self, startPos, homePos, rowCosts, colCosts):\n",
    "        return (sum(rowCosts[startPos[0] + 1 : homePos[0] + 1]) if startPos[0] < homePos[0] else sum(rowCosts[homePos[0] : startPos[0]]) if startPos[0] > homePos[0] else 0) \\\n",
    "             + (sum(colCosts[startPos[1] + 1 : homePos[1] + 1]) if startPos[1] < homePos[1] else sum(colCosts[homePos[1] : startPos[1]]) if startPos[1] > homePos[1] else 0)        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, startPos: List[int], homePos: List[int], rowCosts: List[int], colCosts: List[int]) -> int:\n",
    "\n",
    "        \n",
    "        \n",
    "        minx, maxx = min(startPos[0], homePos[0]), max(startPos[0], homePos[0])\n",
    "        miny, maxy = min(startPos[1], homePos[1]), max(startPos[1], homePos[1])\n",
    "        ret = sum(rowCosts[i] for i in range(minx, maxx + 1)) + sum(colCosts[i] for i in range(miny, maxy + 1))\n",
    "        return ret - rowCosts[startPos[0]] - colCosts[startPos[1]]\n",
    "        \n",
    "        \n",
    "                \n",
    "                "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, startPos: List[int], homePos: List[int], rowCosts: List[int], colCosts: List[int]) -> int:\n",
    "        result = 0\n",
    "        if(startPos[0] > homePos[0]):\n",
    "            result += sum(rowCosts[homePos[0]:startPos[0]])\n",
    "        else:\n",
    "            result += sum(rowCosts[startPos[0]+1:homePos[0]+1])\n",
    "        if(startPos[1] > homePos[1]):\n",
    "            result += sum(colCosts[homePos[1]:startPos[1]])\n",
    "        else:\n",
    "            result += sum(colCosts[startPos[1]+1:homePos[1]+1])\n",
    "        return result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, startPos: List[int], homePos: List[int], rowCosts: List[int], colCosts: List[int]) -> int:\n",
    "        result = 0\n",
    "        for i in self.getSteps(startPos[0], homePos[0]):\n",
    "            result += rowCosts[i]\n",
    "        for i in self.getSteps(startPos[1], homePos[1]):\n",
    "            result += colCosts[i]\n",
    "        return result\n",
    "\n",
    "    def getSteps(self, startPos: int, endPos: int):\n",
    "        step = 1 if startPos <= endPos else -1\n",
    "        return range(startPos + step, endPos + step, step)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, startPos: List[int], homePos: List[int], rowCosts: List[int], colCosts: List[int]) -> int:\n",
    "        result = 0\n",
    "        if(startPos[0] > homePos[0]):\n",
    "            result += sum(rowCosts[homePos[0]:startPos[0]])\n",
    "        else:\n",
    "            result += sum(rowCosts[startPos[0]+1:homePos[0]+1])\n",
    "        if(startPos[1] > homePos[1]):\n",
    "            result += sum(colCosts[homePos[1]:startPos[1]])\n",
    "        else:\n",
    "            result += sum(colCosts[startPos[1]+1:homePos[1]+1])\n",
    "        return result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, startPos: List[int], homePos: List[int], rowCosts: List[int], colCosts: List[int]) -> int:\n",
    "        res = 0\n",
    "        if startPos[0] < homePos[0]:res += sum(rowCosts[startPos[0] + 1:homePos[0] + 1])\n",
    "        else: res += sum(rowCosts[homePos[0]:startPos[0]])\n",
    "        if startPos[1] < homePos[1]:res += sum(colCosts[startPos[1] + 1:homePos[1] + 1])\n",
    "        else: res += sum(colCosts[homePos[1]:startPos[1]])\n",
    "        \n",
    "        return  res"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, startPos: List[int], homePos: List[int], rowCosts: List[int], colCosts: List[int]) -> int:\n",
    "        x0, y0 = startPos\n",
    "        x1, y1= homePos\n",
    "        ans = -rowCosts[x0] - colCosts[y0]\n",
    "        if x0 > x1:\n",
    "            x0, x1 = x1, x0\n",
    "        if y0 > y1:\n",
    "            y0, y1 = y1, y0\n",
    "        for cost in rowCosts[x0:x1+1]:\n",
    "            ans += cost\n",
    "        for cost in colCosts[y0:y1+1]:\n",
    "            ans += cost\n",
    "        return ans"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, startPos: List[int], homePos: List[int], rowCosts: List[int], colCosts: List[int]) -> int:\n",
    "        r1, c1 = startPos[0], startPos[1]\n",
    "        r2, c2 = homePos[0], homePos[1]\n",
    "        res = 0   # 总代价\n",
    "        # 移动至家所在行，判断行间移动方向并计算对应代价\n",
    "        if r2 >= r1:\n",
    "            for i in range(r1 + 1, r2 + 1):\n",
    "                res += rowCosts[i]\n",
    "        else:\n",
    "            for i in range(r2, r1):\n",
    "                res += rowCosts[i]\n",
    "        # 移动至家所在位置，判断列间移动方向并计算对应代价\n",
    "        if c2 >= c1:\n",
    "            for i in range(c1 + 1, c2 + 1):\n",
    "                res += colCosts[i]\n",
    "        else:\n",
    "            for i in range(c2, c1):\n",
    "                res += colCosts[i]\n",
    "        return res"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, startPos: List[int], homePos: List[int], rowCosts: List[int], colCosts: List[int]) -> int:\n",
    "        result = 0\n",
    "        if(startPos[0] > homePos[0]):\n",
    "            result += sum(rowCosts[homePos[0]:startPos[0]])\n",
    "        else:\n",
    "            result += sum(rowCosts[startPos[0]+1:homePos[0]+1])\n",
    "        if(startPos[1] > homePos[1]):\n",
    "            result += sum(colCosts[homePos[1]:startPos[1]])\n",
    "        else:\n",
    "            result += sum(colCosts[startPos[1]+1:homePos[1]+1])\n",
    "        return result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, startPos: List[int], homePos: List[int], rowCosts: List[int], colCosts: List[int]) -> int:\n",
    "        return sum(rowCosts[x] for x in range(min(startPos[0], homePos[0]), max(startPos[0], homePos[0]) + 1)) \\\n",
    "         + sum(colCosts[x] for x in range(min(startPos[1], homePos[1]), max(startPos[1], homePos[1]) + 1)) \\\n",
    "         - rowCosts[startPos[0]] - colCosts[startPos[1]]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, startPos: List[int], homePos: List[int], rowCosts: List[int], colCosts: List[int]) -> int:\n",
    "        x0, y0, x1, y1 = startPos[0], startPos[1], homePos[0], homePos[1]\n",
    "        ans = -rowCosts[x0] - colCosts[y0] # 初始的行列无需计算\n",
    "        if x0 > x1: \n",
    "            x0, x1 = x1, x0 # 交换位置，保证 x0 <= x1\n",
    "        if y0 > y1: \n",
    "            y0, y1 = y1, y0 # 交换位置，保证 y0 <= y1\n",
    "        for cost in rowCosts[x0 : x1+1]:\n",
    "            ans += cost # 统计答案\n",
    "        for cost in colCosts[y0 : y1+1]:\n",
    "            ans += cost # 统计答案\n",
    "        return ans"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, startPos: List[int], homePos: List[int], rowCosts: List[int], colCosts: List[int]) -> int:\n",
    "        ans = 0\n",
    "        if startPos[0] != homePos[0]:\n",
    "            if startPos[0] < homePos[0]:\n",
    "                ans += sum(rowCosts[startPos[0]+1:homePos[0]+1])\n",
    "            else:\n",
    "                ans += sum(rowCosts[homePos[0]:startPos[0]])\n",
    "        if startPos[1] != homePos[1]:\n",
    "            if startPos[1] < homePos[1]:\n",
    "                ans += sum(colCosts[startPos[1]+1:homePos[1]+1])\n",
    "            else:\n",
    "                ans += sum(colCosts[homePos[1]:startPos[1]])\n",
    "        return ans"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, startPos: List[int], homePos: List[int], rowCosts: List[int], colCosts: List[int]) -> int:\n",
    "        si, sj = startPos\n",
    "        ei, ej = homePos\n",
    "        \n",
    "        si, ei = (si, ei) if si <= ei else (ei, si)\n",
    "        sj, ej = (sj, ej) if sj <= ej else (ej, sj)\n",
    "\n",
    "        return (\n",
    "            sum(rowCosts[si:ei + 1])\n",
    "            + sum(colCosts[sj:ej + 1])\n",
    "            - rowCosts[startPos[0]]\n",
    "            - colCosts[startPos[1]]\n",
    "        )\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, startPos: List[int], homePos: List[int], rowCosts: List[int], colCosts: List[int]) -> int:\n",
    "        # 代价都是正的，所以不可绕路\n",
    "        # 贪心找x, y 较小分量即可\n",
    "        x1, y1, x2, y2 = startPos[0], startPos[1], homePos[0], homePos[1]\n",
    "\n",
    "        ans = -rowCosts[x1] - colCosts[y1]\n",
    "        # 水平移动代价\n",
    "        if x1 > x2:\n",
    "            x1, x2 = x2, x1\n",
    "        for i in range(x1, x2+1):\n",
    "            ans += rowCosts[i]\n",
    "        \n",
    "        # 垂直移动代价\n",
    "        if y1 > y2:\n",
    "            y1, y2 = y2, y1\n",
    "        for i in range(y1, y2+1):\n",
    "            ans += colCosts[i]\n",
    "        \n",
    "        return ans\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, startPos: List[int], homePos: List[int], rowCosts: List[int], colCosts: List[int]) -> int:\n",
    "\n",
    "        if homePos == startPos:\n",
    "            return 0\n",
    "\n",
    "        st = startPos[0]\n",
    "        flag = 1\n",
    "        if startPos[0] > homePos[0]:\n",
    "            flag = -1 \n",
    "        cst = 0\n",
    "        while st != homePos[0]:\n",
    "            st += flag\n",
    "            cst += rowCosts[st]\n",
    "\n",
    "        st = startPos[1]\n",
    "        flag = 1\n",
    "        if startPos[1] > homePos[1]:\n",
    "            flag = -1 \n",
    "\n",
    "        while st != homePos[1]:\n",
    "            st += flag\n",
    "            cst += colCosts[st]\n",
    "\n",
    "        return cst        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, startPos: List[int], homePos: List[int], rowCosts: List[int], colCosts: List[int]) -> int:\n",
    "        rmin = min(startPos[0], homePos[0])\n",
    "        rmax = max(startPos[0], homePos[0])\n",
    "        cmin = min(startPos[1], homePos[1])\n",
    "        cmax = max(startPos[1], homePos[1])\n",
    "\n",
    "        ans = sum(rowCosts[rmin:rmax+1]) + sum(colCosts[cmin:cmax+1])\n",
    "        ans -= rowCosts[startPos[0]]\n",
    "        ans -= colCosts[startPos[1]]\n",
    "        return ans"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, startPos: List[int], homePos: List[int], rowCosts: List[int], colCosts: List[int]) -> int:\n",
    "        x,y=startPos[0],startPos[1]\n",
    "        a,b=homePos[0],homePos[1]\n",
    "        ans=0\n",
    "        if x<a:\n",
    "            ans+=sum(rowCosts[x+1:a+1])\n",
    "        else:\n",
    "            ans+=sum(rowCosts[a:x])\n",
    "        if y<b:\n",
    "            ans+=sum(colCosts[y+1:b+1])\n",
    "        else:\n",
    "            ans+=sum(colCosts[b:y])\n",
    "        return ans"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, startPos: List[int], homePos: List[int], rowCosts: List[int], colCosts: List[int]) -> int:\n",
    "        r1, c1 = startPos[0], startPos[1]\n",
    "        r2, c2 = homePos[0], homePos[1]\n",
    "        res = 0   # 总代价\n",
    "        # 移动至家所在行，判断行间移动方向并计算对应代价\n",
    "        if r2 >= r1:\n",
    "            for i in range(r1 + 1, r2 + 1):\n",
    "                res += rowCosts[i]\n",
    "        else:\n",
    "            for i in range(r2, r1):\n",
    "                res += rowCosts[i]\n",
    "        # 移动至家所在位置，判断列间移动方向并计算对应代价\n",
    "        if c2 >= c1:\n",
    "            for i in range(c1 + 1, c2 + 1):\n",
    "                res += colCosts[i]\n",
    "        else:\n",
    "            for i in range(c2, c1):\n",
    "                res += colCosts[i]\n",
    "        return res"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, startPos: List[int], homePos: List[int], rowCosts: List[int], colCosts: List[int]) -> int:\n",
    "        startRow, endRow = startPos[0], homePos[0]\n",
    "        startCol, endCol = startPos[1], homePos[1]\n",
    "        ans = 0\n",
    "        if startRow < endRow:\n",
    "            for i in range(startRow + 1, endRow + 1):\n",
    "                ans += rowCosts[i]\n",
    "        else:\n",
    "            for i in range(startRow - 1, endRow - 1, -1):\n",
    "                ans += rowCosts[i]\n",
    "        if startCol < endCol:\n",
    "            for i in range(startCol + 1, endCol + 1):\n",
    "                ans += colCosts[i]\n",
    "        else:\n",
    "            for i in range(startCol - 1, endCol - 1, -1):\n",
    "                ans += colCosts[i]\n",
    "        return ans"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from typing import List\n",
    "\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, startPos: List[int], homePos: List[int], rowCosts: List[int], colCosts: List[int]) -> int:\n",
    "        result = 0\n",
    "        for i in self.getSteps(startPos[0], homePos[0]):\n",
    "            result += rowCosts[i]\n",
    "        for i in self.getSteps(startPos[1], homePos[1]):\n",
    "            result += colCosts[i]\n",
    "        return result\n",
    "\n",
    "    def getSteps(self, startPos: int, endPos: int):\n",
    "        step = 1 if startPos <= endPos else -1\n",
    "        return range(startPos + step, endPos + step, step)\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    print(list(Solution().getSteps(5,2)))\n",
    "    print(Solution().minCost([5,5] ,[5,2] ,[7,1,3,3,5,3,22,10,23],[5,5,6,2,0,16]))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, startPos: List[int], homePos: List[int], rowCosts: List[int], colCosts: List[int]) -> int:\n",
    "        ans=0\n",
    "        step= -1 if startPos[0]>homePos[0] else 1\n",
    "        for i in range(startPos[0]+step, homePos[0]+step, step):\n",
    "            ans+=rowCosts[i]\n",
    "        step= -1 if startPos[1]>homePos[1] else 1\n",
    "        for i in range(startPos[1], homePos[1], step):\n",
    "            ans+=colCosts[i+step]\n",
    "        return ans"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, startPos: List[int], homePos: List[int], rowCosts: List[int], colCosts: List[int]) -> int:\n",
    "        sx, sy = startPos\n",
    "        hx, hy = homePos\n",
    "        \n",
    "        ans = 0\n",
    "        if sx <= hx:\n",
    "            ans += sum(rowCosts[i] for i in range(sx+1, hx+1))\n",
    "        else:\n",
    "            ans += sum(rowCosts[i] for i in range(hx, sx))\n",
    "        \n",
    "        if sy <= hy:\n",
    "            ans += sum(colCosts[i] for i in range(sy+1, hy+1))\n",
    "        else:\n",
    "            ans += sum(colCosts[i] for i in range(hy, sy))\n",
    "        \n",
    "        return ans\n",
    "            \n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, startPos: List[int], homePos: List[int], rowCosts: List[int], colCosts: List[int]) -> int:\n",
    "        ans=0\n",
    "        step= -1 if startPos[0]>homePos[0] else 1\n",
    "        for i in range(startPos[0], homePos[0], step):\n",
    "            ans+=rowCosts[i+step]\n",
    "        step= -1 if startPos[1]>homePos[1] else 1\n",
    "        for i in range(startPos[1], homePos[1], step):\n",
    "            ans+=colCosts[i+step]\n",
    "        return ans"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, startPos: List[int], homePos: List[int], rowCosts: List[int], colCosts: List[int]) -> int:\n",
    "        if startPos == homePos:\n",
    "            return 0\n",
    "\n",
    "\n",
    "        def hp(h, s, costs):\n",
    "            dx = h - s \n",
    "\n",
    "            ans = 0\n",
    "\n",
    "            if dx == 0:\n",
    "                pass\n",
    "            elif dx > 0:\n",
    "                for k in range(s + 1, h + 1):\n",
    "                    ans += costs[k]\n",
    "            else:\n",
    "                for k in range(h, s):\n",
    "                    ans += costs[k]\n",
    "            \n",
    "            return ans\n",
    "\n",
    "        return hp(homePos[0], startPos[0], rowCosts) + hp(homePos[1], startPos[1], colCosts)\n",
    "\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, startPos: List[int], homePos: List[int], rowCosts: List[int], colCosts: List[int]) -> int:\n",
    "        dx, dy = 0, 0\n",
    "        if startPos[0] <= homePos[0]:\n",
    "            dx = 1\n",
    "        else:\n",
    "            dx = -1\n",
    "        \n",
    "        if startPos[1] <= homePos[1]:\n",
    "            dy = 1\n",
    "        else:\n",
    "            dy = -1\n",
    "        \n",
    "        return sum(rowCosts[i] for i in range(startPos[0] + dx, homePos[0] + dx, dx)) + sum(colCosts[i] for i in range(startPos[1] + dy, homePos[1] + dy, dy))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, startPos: List[int], homePos: List[int], rowCosts: List[int], colCosts: List[int]) -> int:\n",
    "        ans=0\n",
    "        step= -1 if startPos[0]>homePos[0] else 1\n",
    "        for i in range(startPos[0]+step, homePos[0]+step, step):\n",
    "            ans+=rowCosts[i]\n",
    "        step= -1 if startPos[1]>homePos[1] else 1\n",
    "        for i in range(startPos[1]+step, homePos[1]+step, step):\n",
    "            ans+=colCosts[i]\n",
    "        return ans"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, startPos: List[int], homePos: List[int], rowCosts: List[int], colCosts: List[int]) -> int:\n",
    "        row_diff = homePos[0] - startPos[0]\n",
    "        col_diff = homePos[1] - startPos[1]\n",
    "        now_pos = startPos\n",
    "        cost = 0\n",
    "        while now_pos != homePos:\n",
    "            if row_diff > 0:\n",
    "                cost += rowCosts[now_pos[0] + 1]\n",
    "                now_pos[0] += 1\n",
    "                row_diff -= 1\n",
    "            elif row_diff < 0:\n",
    "                cost += rowCosts[now_pos[0] - 1]\n",
    "                now_pos[0] -= 1\n",
    "                row_diff += 1\n",
    "\n",
    "            if col_diff > 0:\n",
    "                cost += colCosts[now_pos[1] + 1]\n",
    "                now_pos[1] += 1\n",
    "                col_diff -= 1\n",
    "            elif col_diff < 0:\n",
    "                cost += colCosts[now_pos[1] - 1]\n",
    "                now_pos[1] -= 1\n",
    "                col_diff += 1\n",
    "        return cost"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, s: List[int], h: List[int], rowCosts: List[int], colCosts: List[int]) -> int:\n",
    "        res = 0\n",
    "        if s[0] <= h[0]:\n",
    "            for i in range(min(s[0],h[0])+1,max(s[0],h[0])+1):\n",
    "                res += rowCosts[i]\n",
    "        else:\n",
    "            for i in range(s[0]-1,h[0]-1,-1):\n",
    "                res += rowCosts[i]\n",
    "        if s[1] <= h[1]:\n",
    "            for i in range(min(s[1],h[1])+1,max(s[1],h[1])+1):\n",
    "                res += colCosts[i]\n",
    "        else:\n",
    "            for i in range(s[1]-1,h[1]-1,-1):\n",
    "                res += colCosts[i]\n",
    "        return res"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, startPos: List[int], homePos: List[int], rowCosts: List[int], colCosts: List[int]) -> int:\n",
    "        if startPos[0]>homePos[0]:\n",
    "            dx=-1\n",
    "        else:\n",
    "            dx=1\n",
    "        if startPos[1]>homePos[1]:\n",
    "            dy=-1\n",
    "        else:\n",
    "            dy=1\n",
    "        ans=0\n",
    "        for i in range(startPos[0]+dx, homePos[0]+dx, dx):\n",
    "            ans+=rowCosts[i]\n",
    "        for i in range(startPos[1]+dy, homePos[1]+dy, dy):\n",
    "            ans+=colCosts[i]\n",
    "        return ans"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, startPos: List[int], homePos: List[int], rowCosts: List[int], colCosts: List[int]) -> int:\n",
    "        r1, c1 = startPos[0], startPos[1]\n",
    "        r2, c2 = homePos[0], homePos[1]\n",
    "        res = 0   # 总代价\n",
    "        # 移动至家所在行，判断行间移动方向并计算对应代价\n",
    "        if r2 >= r1:\n",
    "            for i in range(r1 + 1, r2 + 1):\n",
    "                res += rowCosts[i]\n",
    "        else:\n",
    "            for i in range(r2, r1):\n",
    "                res += rowCosts[i]\n",
    "        # 移动至家所在位置，判断列间移动方向并计算对应代价\n",
    "        if c2 >= c1:\n",
    "            for i in range(c1 + 1, c2 + 1):\n",
    "                res += colCosts[i]\n",
    "        else:\n",
    "            for i in range(c2, c1):\n",
    "                res += colCosts[i]\n",
    "        return res"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, s: List[int], h: List[int], rs: List[int], cs: List[int]) -> int:\n",
    "        if s[0] == h[0] and s[1] == h[1]:\n",
    "            return 0\n",
    "        r, c = len(rs), len(cs)\n",
    "        \n",
    "        ans = 0\n",
    "        row_s, row_e = s[0], h[0]\n",
    "        if row_s >= row_e:\n",
    "            for i in range(row_s-1, row_e-1,-1):\n",
    "                ans += rs[i]\n",
    "        else:\n",
    "            for i in range(row_s+1, row_e+1):\n",
    "                ans += rs[i]\n",
    "\n",
    "        col_s, col_e = s[1], h[1]\n",
    "        if col_s >= col_e:\n",
    "            for i in range(col_s-1, col_e-1,-1):\n",
    "                ans += cs[i]\n",
    "        else:\n",
    "            for i in range(col_s+1, col_e+1):\n",
    "                ans += cs[i]\n",
    "        return ans"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, startPos: List[int], homePos: List[int], rowCosts: List[int], colCosts: List[int]) -> int:\n",
    "        ans1=0\n",
    "        ans2=0\n",
    "        if startPos==homePos:\n",
    "            return 0\n",
    "        while startPos[0]!=homePos[0]:\n",
    "            if startPos[0]>homePos[0]:\n",
    "                startPos[0]-=1\n",
    "                ans1+=rowCosts[startPos[0]]\n",
    "            if startPos[0]<homePos[0]:\n",
    "                startPos[0]+=1\n",
    "                ans1+=rowCosts[startPos[0]]\n",
    "        while startPos[1]!=homePos[1]:\n",
    "            if startPos[1]>homePos[1]:\n",
    "                startPos[1]-=1\n",
    "                ans2+=colCosts[startPos[1]]\n",
    "            if startPos[1]<homePos[1]:\n",
    "                startPos[1]+=1\n",
    "                ans2+=colCosts[startPos[1]]\n",
    "        return (ans1+ans2)\n",
    "                \n",
    "\n",
    "\n",
    "\n",
    "       \n",
    "\n",
    "        \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, startPos: List[int], homePos: List[int], rowCosts: List[int], colCosts: List[int]) -> int:\n",
    "\n",
    "        x1, y1 = startPos\n",
    "        x2, y2 = homePos\n",
    "        res = 0\n",
    "        if x1 <= x2:\n",
    "            for i in range(x1+1, x2+1):\n",
    "                res += rowCosts[i]\n",
    "        else:\n",
    "            for i in range(x2, x1):\n",
    "                res += rowCosts[i]\n",
    "        if y1 <= y2:\n",
    "            for j in range(y1+1, y2+1):\n",
    "                res += colCosts[j]\n",
    "        else:\n",
    "            for j in range(y2, y1):\n",
    "                res += colCosts[j]\n",
    "        return res"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, startPos: List[int], homePos: List[int], rowCosts: List[int], colCosts: List[int]) -> int:\n",
    "        row_delta = col_delta = 1\n",
    "        if startPos[0] > homePos[0]:\n",
    "            row_delta = -1\n",
    "        if startPos[1] > homePos[1]:\n",
    "            col_delta = -1\n",
    "        \n",
    "        res = 0\n",
    "        for index in range(startPos[0] + row_delta, homePos[0] + row_delta, row_delta):\n",
    "            res += rowCosts[index]\n",
    "        for index in range(startPos[1] + col_delta, homePos[1] + col_delta, col_delta):\n",
    "            res += colCosts[index]\n",
    "        \n",
    "        return res"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, startPos: List[int], homePos: List[int], rowCosts: List[int], colCosts: List[int]) -> int:\n",
    "        r1, c1 = startPos[0], startPos[1]\n",
    "        r2, c2 = homePos[0], homePos[1]\n",
    "        res = 0   # 总代价\n",
    "        # 移动至家所在行，判断行间移动方向并计算对应代价\n",
    "        if r2 >= r1:\n",
    "            for i in range(r1 + 1, r2 + 1):\n",
    "                res += rowCosts[i]\n",
    "        else:\n",
    "            for i in range(r2, r1):\n",
    "                res += rowCosts[i]\n",
    "        # 移动至家所在位置，判断列间移动方向并计算对应代价\n",
    "        if c2 >= c1:\n",
    "            for i in range(c1 + 1, c2 + 1):\n",
    "                res += colCosts[i]\n",
    "        else:\n",
    "            for i in range(c2, c1):\n",
    "                res += colCosts[i]\n",
    "        return res"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution(object):\n",
    "    def minCost(self, startPos, homePos, rowCosts, colCosts):\n",
    "        return (sum(rowCosts[startPos[0] + 1 : homePos[0] + 1]) if startPos[0] < homePos[0] else sum(rowCosts[homePos[0] : startPos[0]]) if startPos[0] > homePos[0] else 0) \\\n",
    "             + (sum(colCosts[startPos[1] + 1 : homePos[1] + 1]) if startPos[1] < homePos[1] else sum(colCosts[homePos[1] : startPos[1]]) if startPos[1] > homePos[1] else 0)        \n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "       \n",
    "\n",
    "        \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, startPos: List[int], homePos: List[int], rowCosts: List[int], colCosts: List[int]) -> int:\n",
    "        # dfs(i,j)从i，j到达终点的最小代价\n",
    "        # 因为cost都是正数，如果又绕过来l肯定代价会更大\n",
    "        sx,sy,tx,ty=startPos[0],startPos[1],homePos[0],homePos[1]\n",
    "        res=0\n",
    "        if sx<tx:\n",
    "            for row in range(sx+1,tx+1):\n",
    "                res+=rowCosts[row]\n",
    "        elif sx>tx:\n",
    "            for row in range(sx-1,tx-1,-1):\n",
    "                res+=rowCosts[row]\n",
    "        if sy<ty:\n",
    "            for row in range(sy+1,ty+1):\n",
    "                res+=colCosts[row]\n",
    "        elif sy>ty:\n",
    "            for row in range(sy-1,ty-1,-1):\n",
    "                res+=colCosts[row]\n",
    "        return res "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, startPos: List[int], homePos: List[int], rowCosts: List[int], colCosts: List[int]) -> int:\n",
    "        rs = 0\n",
    "        for i in range(min(startPos[0], homePos[0]), max(startPos[0], homePos[0])+1):\n",
    "            rs += rowCosts[i]\n",
    "        for j in range(min(startPos[1], homePos[1]), max(startPos[1], homePos[1])+1):\n",
    "            rs += colCosts[j]\n",
    "        return rs-colCosts[startPos[1]]-rowCosts[startPos[0]]\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, startPos: List[int], homePos: List[int], rowCosts: List[int], colCosts: List[int]) -> int:\n",
    "        r1, c1 = startPos[0], startPos[1]\n",
    "        r2, c2 = homePos[0], homePos[1]\n",
    "        res = 0  # 总代价\n",
    "        # 移动至家所在行，判断行间移动方向并计算对应代价\n",
    "        if r2 >= r1:\n",
    "            for i in range(r1 + 1, r2 + 1):\n",
    "                res += rowCosts[i]\n",
    "        else:\n",
    "            for i in range(r2, r1):\n",
    "                res += rowCosts[i]\n",
    "        # 移动至家所在位置，判断列间移动方向并计算对应代价\n",
    "        if c2 >= c1:\n",
    "            for i in range(c1 + 1, c2 + 1):\n",
    "                res += colCosts[i]\n",
    "        else:\n",
    "            for i in range(c2, c1):\n",
    "                res += colCosts[i]\n",
    "        return res"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, startPos: List[int], homePos: List[int], rowCosts: List[int], colCosts: List[int]) -> int:\n",
    "        y1, x1 = startPos\n",
    "        y2, x2 = homePos\n",
    "        if y1 <= y2:\n",
    "            dy = 1\n",
    "        else:\n",
    "            dy = -1\n",
    "        if x1 <= x2:\n",
    "            dx = 1\n",
    "        else:\n",
    "            dx = -1\n",
    "        ret = sum(rowCosts[y] for y in range(y1+dy, y2+dy, dy))\n",
    "        ret += sum(colCosts[x] for x in range(x1+dx, x2+dx, dx))\n",
    "        return ret\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minimumCost(self, start: list[int], target: list[int], specialRoads: list[list[int]]) -> int:\n",
    "        nodes = set([tuple(start), tuple(target)])\n",
    "        cost = collections.defaultdict(int)\n",
    "\n",
    "        for x1, y1, x2, y2, c in specialRoads:\n",
    "            if (x1, y1, x2, y2) not in cost:\n",
    "                cost[(x1, y1, x2, y2)] = c\n",
    "            else:\n",
    "                cost[(x1, y1, x2, y2)] = min(cost[(x1, y1, x2, y2)], c)\n",
    "            nodes.add((x1, y1))\n",
    "            nodes.add((x2, y2))\n",
    "\n",
    "        minHeap = [(0, start[0], start[1])]\n",
    "        visited = set()\n",
    "        minCost = {node: float('inf') for node in nodes}\n",
    "        minCost[(start[0], start[1])] = 0\n",
    "\n",
    "        while minHeap:\n",
    "            c, x, y = heapq.heappop(minHeap)\n",
    "            if (x, y) in visited:\n",
    "                continue\n",
    "            visited.add((x, y))\n",
    "\n",
    "            for nx, ny in nodes:\n",
    "                if (nx, ny) not in visited:\n",
    "                    sc = cost[(x, y, nx, ny)] if (x, y, nx, ny) in cost else float('inf')\n",
    "                    nc = min(sc, abs(nx-x)+abs(ny-y)) + c\n",
    "                    if nc < minCost[(nx, ny)]:\n",
    "                        minCost[(nx, ny)] = nc\n",
    "                        heapq.heappush(minHeap, (nc, nx, ny))\n",
    "\n",
    "        return minCost[(target[0], target[1])]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "import heapq\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, roads: List[List[int]], appleCost: List[int], k: int) -> List[int]:\n",
    "        ans = [-1]*n\n",
    "        g = [[] for _ in range(n)]\n",
    "        for a,b,c in roads:\n",
    "            g[a-1].append((b-1, c))\n",
    "            g[b-1].append((a-1, c))\n",
    "        \n",
    "        def dijkstra(start):\n",
    "            dist = [float('inf')]*n\n",
    "            dist[start] = 0\n",
    "            mheap = [(0,start)]\n",
    "            while mheap:\n",
    "                dis,x = heapq.heappop(mheap)\n",
    "                if dis>dist[x]:\n",
    "                    continue\n",
    "                for nextN,nextD in g[x]:\n",
    "                    if dis+nextD < dist[nextN]:\n",
    "                        dist[nextN] = dis+nextD\n",
    "                        heapq.heappush(mheap, (dist[nextN], nextN))\n",
    "                pass\n",
    "            \n",
    "            cur_min = float('inf')\n",
    "            for i in range(n):\n",
    "                cur = (k+1)*dist[i] + appleCost[i]\n",
    "                cur_min = min(cur_min, cur) \n",
    "            return cur_min\n",
    "\n",
    "        for i in range(n):\n",
    "            ans[i] = dijkstra(i)\n",
    "        return ans"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, roads: List[List[int]], appleCost: List[int], k: int) -> List[int]:\n",
    "        e=collections.defaultdict(list)\n",
    "        for a,b,c in roads:\n",
    "            e[a].append((b,c*k+c))\n",
    "            e[b].append((a,c*k+c))\n",
    "        def dijk(start):\n",
    "            q=[(0,start)]\n",
    "            ret=appleCost[start-1]\n",
    "            find=[False]*(n+1)\n",
    "            while q:\n",
    "                cost,tp=heapq.heappop(q)\n",
    "                ret=min(ret,cost+appleCost[tp-1])\n",
    "                if find[tp]:\n",
    "                    continue\n",
    "                find[tp]=True\n",
    "                for i,newcost in e[tp]:\n",
    "                    if find[i]:\n",
    "                        continue\n",
    "                    heapq.heappush(q,(cost+newcost,i))\n",
    "            return  ret \n",
    "        ans=[0]*n\n",
    "        for i in range(n):\n",
    "            ans[i]=dijk(i+1)\n",
    "        return ans"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, roads: List[List[int]], appleCost: List[int], k: int) -> List[int]:\n",
    "        g = collections.defaultdict(list)\n",
    "        for a, b, c in roads:\n",
    "            g[a - 1].append((b - 1, c * (k + 1)))\n",
    "            g[b - 1].append((a - 1, c * (k + 1)))\n",
    "\n",
    "        visited = [0] * n\n",
    "        pq = sorted((c, i) for i, c in enumerate(appleCost))\n",
    "        while pq:\n",
    "            c, u = heapq.heappop(pq)\n",
    "            if visited[u]:\n",
    "                continue\n",
    "\n",
    "            visited[u] = 1\n",
    "            for v, nc in g[u]:\n",
    "                if appleCost[v] > c + nc:\n",
    "                    appleCost[v] = c + nc\n",
    "                    heapq.heappush(pq, (appleCost[v], v))\n",
    "\n",
    "        return appleCost\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from heapq import heappop, heappush\n",
    "from math import inf\n",
    "from typing import List\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, roads: List[List[int]], appleCost: List[int], k: int) -> List[int]:\n",
    "        adj = [[] for _ in range(n + 1)]\n",
    "        for u, v, cost in roads:\n",
    "            u -= 1\n",
    "            v -= 1\n",
    "            adj[u].append((v, (k + 1) * cost))\n",
    "            adj[v].append((u, (k + 1) * cost))\n",
    "        \n",
    "        # node n represents apple\n",
    "        for i, c in enumerate(appleCost):\n",
    "            adj[i].append((n, c))\n",
    "            adj[n].append((i, c))\n",
    "\n",
    "        # Dijkstra find shortest path from node n (apple) to every node\n",
    "        dist = [inf] * n + [0]\n",
    "        # heap stores (cost, node)\n",
    "        h = [(0, n)]\n",
    "        while h:\n",
    "            d, u = heappop(h)\n",
    "            if dist[u] < d:\n",
    "                continue\n",
    "            for v, w in adj[u]:\n",
    "                if dist[v] > d + w:\n",
    "                    dist[v] = d + w\n",
    "                    heappush(h, (d + w, v))\n",
    "            \n",
    "        return dist[:n]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, roads: List[List[int]], appleCost: List[int], k: int) -> List[int]:\n",
    "        g = collections.defaultdict(list)\n",
    "        for a, b, c in roads:\n",
    "            g[a - 1].append((b - 1, c * (k + 1)))\n",
    "            g[b - 1].append((a - 1, c * (k + 1)))\n",
    "\n",
    "        visited = [0] * n\n",
    "        pq = sorted((c, i) for i, c in enumerate(appleCost))\n",
    "        while pq:\n",
    "            c, u = heapq.heappop(pq)\n",
    "            if visited[u]:\n",
    "                continue\n",
    "\n",
    "            visited[u] = 1\n",
    "            for v, nc in g[u]:\n",
    "                if appleCost[v] > c + nc:\n",
    "                    appleCost[v] = c + nc\n",
    "                    heapq.heappush(pq, (appleCost[v], v))\n",
    "\n",
    "        return appleCost\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, roads: List[List[int]], appleCost: List[int], k: int) -> List[int]:\n",
    "        cost = appleCost[::]\n",
    "        g = defaultdict(list)\n",
    "        for u, v, w in roads:\n",
    "            x, y, z = u - 1, v - 1, (k + 1) * w\n",
    "            g[x].append((y, z))\n",
    "            g[y].append((x, z))\n",
    "        h = []\n",
    "        for i, x in enumerate(appleCost):\n",
    "            heappush(h, (x,i))\n",
    "        while h:\n",
    "            cost, x = heappop(h)\n",
    "            if cost > appleCost[x]: continue\n",
    "            for y, w in g[x]:\n",
    "                if cost + w < appleCost[y]:\n",
    "                    appleCost[y] = cost + w \n",
    "                    heappush(h, (appleCost[y], y))\n",
    "        return appleCost\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, roads: List[List[int]], appleCost: List[int], k: int) -> List[int]:\n",
    "        g = defaultdict(list)\n",
    "        for a, b, cost in roads:\n",
    "            g[a - 1].append([b - 1, cost])\n",
    "            g[b - 1].append([a - 1, cost])\n",
    "        \n",
    "        def dijkstra(start):\n",
    "            ans = inf\n",
    "            dist = [inf] * n\n",
    "            dist[start] = 0\n",
    "            q = [(0, start)]\n",
    "            while q:\n",
    "                cost, node = heapq.heappop(q)\n",
    "                ans = min(ans, cost * (k + 1) + appleCost[node])\n",
    "                if dist[node] < cost:\n",
    "                    continue\n",
    "                for nei, cost in g[node]:\n",
    "                    d = dist[node] + cost\n",
    "                    if d < dist[nei]:\n",
    "                        dist[nei] = d\n",
    "                        heapq.heappush(q, (d, nei))\n",
    "            return ans\n",
    "        return [dijkstra(i) for i in range(n)]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, roads: List[List[int]], appleCost: List[int], k: int) -> List[int]:\n",
    "        g = defaultdict(list)\n",
    "        for u, v, w in roads:\n",
    "            g[u - 1].append((v - 1, w))\n",
    "            g[v - 1].append((u - 1, w))\n",
    "        def dijkstra(i):\n",
    "            pq, visited, res = [(0, i)], set(), inf\n",
    "            while pq:\n",
    "                w, node = heappop(pq)\n",
    "                if node not in visited:\n",
    "                    visited.add(node)\n",
    "                    res = min(res, w + appleCost[node])\n",
    "                    for nei, weight in g[node]:\n",
    "                        heappush(pq, (w + weight * (k + 1), nei))\n",
    "            return res\n",
    "        return [dijkstra(i) for i in range(n)]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, roads: List[List[int]], appleCost: List[int], k: int) -> List[int]:\n",
    "        g = defaultdict(list)\n",
    "        for a, b, cost in roads:\n",
    "            g[a - 1].append([b - 1, cost])\n",
    "            g[b - 1].append([a - 1, cost])\n",
    "        \n",
    "        def dijkstra(start):\n",
    "            res, dist = inf, [inf] * n\n",
    "            dist[start], q = 0, [(0, start)]\n",
    "            while q:\n",
    "                cost, node = heapq.heappop(q)\n",
    "                res = min(res, cost * (k + 1) + appleCost[node])\n",
    "                for nei, cost in g[node]:\n",
    "                    d = dist[node] + cost\n",
    "                    if d < dist[nei]:\n",
    "                        dist[nei] = d\n",
    "                        heapq.heappush(q, (d, nei))\n",
    "            return res\n",
    "        return [dijkstra(i) for i in range(n)]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, roads: List[List[int]], appleCost: List[int], k: int) -> List[int]:\n",
    "        adj = [[] for _ in range(n + 1)]\n",
    "        for u, v, cost in roads:\n",
    "            u -= 1\n",
    "            v -= 1\n",
    "            adj[u].append((v, (k + 1) * cost))\n",
    "            adj[v].append((u, (k + 1) * cost))\n",
    "        \n",
    "        # node n represents apple\n",
    "        for i, c in enumerate(appleCost):\n",
    "            adj[i].append((n, c))\n",
    "            adj[n].append((i, c))\n",
    "\n",
    "        # Dijkstra find shortest path from node n (apple) to every node\n",
    "        dist = [inf] * n + [0]\n",
    "        # heap stores (cost, node)\n",
    "        h = [(0, n)]\n",
    "        while h:\n",
    "            d, u = heappop(h)\n",
    "            if dist[u] < d:\n",
    "                continue\n",
    "            for v, w in adj[u]:\n",
    "                if dist[v] > d + w:\n",
    "                    dist[v] = d + w\n",
    "                    heappush(h, (d + w, v))\n",
    "            \n",
    "        return dist[:n]\n",
    "                "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, roads: List[List[int]], appleCost: List[int], k: int) -> List[int]:\n",
    "        g = defaultdict(list)\n",
    "        for a, b, cost in roads:\n",
    "            g[a - 1].append([b - 1, cost])\n",
    "            g[b - 1].append([a - 1, cost])\n",
    "        \n",
    "        def dijkstra(start: int):\n",
    "            ans = float('inf')\n",
    "            dist = [float('inf')] * n\n",
    "            dist[start] = 0\n",
    "            q = [(0, start)]\n",
    "            while q:\n",
    "                cost, x = heapq.heappop(q)\n",
    "                ans = min(ans, cost * (k + 1) + appleCost[x])\n",
    "                if dist[x] < cost:\n",
    "                    continue\n",
    "                for y, cost in g[x]:\n",
    "                    d = dist[x] + cost\n",
    "                    if d < dist[y]:\n",
    "                        dist[y] = d\n",
    "                        heapq.heappush(q, (d, y))\n",
    "            return ans\n",
    "        \n",
    "        ans = [0] * n\n",
    "        for i in range(n):\n",
    "            ans[i] = dijkstra(i)\n",
    "        return ans\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, roads: List[List[int]], appleCost: List[int], k: int) -> List[int]:\n",
    "        graph = [set() for i in range(n + 1)]\n",
    "        for i, j, w in roads:\n",
    "            graph[i].add((j, w * (k + 1)))\n",
    "            graph[j].add((i, w * (k + 1)))\n",
    "        for j, w in enumerate(appleCost):\n",
    "            graph[0].add((j + 1, w))\n",
    "\n",
    "        answer = [100000] * (n + 1)\n",
    "        apple = []\n",
    "        answer[0] = 0\n",
    "        queue = [(0, 0)]\n",
    "        while len(queue) != 0:\n",
    "            nextW, nextP = heapq.heappop(queue)\n",
    "            if nextW > answer[nextP]:\n",
    "                continue\n",
    "            for each, eachW in graph[nextP]:\n",
    "                tmp = nextW + eachW\n",
    "                if answer[each] > tmp:\n",
    "                    answer[each] = tmp\n",
    "                    heapq.heappush(queue, (tmp, each))\n",
    "\n",
    "        return answer[1:]\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, roads: List[List[int]], appleCost: List[int], k: int) -> List[int]:\n",
    "        g = defaultdict(list)\n",
    "        for u, v, w in roads:\n",
    "            g[u - 1].append((v - 1, w))\n",
    "            g[v - 1].append((u - 1, w))\n",
    "        def dijkstra(i):\n",
    "            pq, d, res = [(0, i)], defaultdict(int), inf\n",
    "            while pq:\n",
    "                w, node = heappop(pq)\n",
    "                if node not in d:\n",
    "                    d[node] = w + appleCost[node]\n",
    "                    res = min(res, d[node])\n",
    "                    for nei, weight in g[node]:\n",
    "                        heappush(pq, (w + weight * (k + 1), nei))\n",
    "            return res\n",
    "        return [dijkstra(i) for i in range(n)]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\r\n",
    "    def minCost(self, n: int, roads: List[List[int]], appleCost: List[int], k: int) -> List[int]:\r\n",
    "        g = defaultdict(list)\r\n",
    "        for a, b, cost in roads:\r\n",
    "            g[a - 1].append([b - 1, cost])\r\n",
    "            g[b - 1].append([a - 1, cost])\r\n",
    "        \r\n",
    "        def dijkstra(start: int):\r\n",
    "            ans = float('inf')\r\n",
    "            dist = [float('inf')] * n\r\n",
    "            dist[start] = 0\r\n",
    "            q = [(0, start)]\r\n",
    "            while q:\r\n",
    "                cost, x = heapq.heappop(q)\r\n",
    "                ans = min(ans, cost * (k + 1) + appleCost[x])\r\n",
    "                if dist[x] < cost:\r\n",
    "                    continue\r\n",
    "                for y, cost in g[x]:\r\n",
    "                    d = dist[x] + cost\r\n",
    "                    if d < dist[y]:\r\n",
    "                        dist[y] = d\r\n",
    "                        heapq.heappush(q, (d, y))\r\n",
    "            return ans\r\n",
    "        \r\n",
    "        ans = [0] * n\r\n",
    "        for i in range(n):\r\n",
    "            ans[i] = dijkstra(i)\r\n",
    "        return ans"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, roads: List[List[int]], appleCost: List[int], k: int) -> List[int]:\n",
    "        g = defaultdict(list)\n",
    "        for u, v, w in roads:\n",
    "            g[u - 1].append((v - 1, w))\n",
    "            g[v - 1].append((u - 1, w))\n",
    "        def dijkstra(i):\n",
    "            pq, d = [(0, i)], defaultdict(int)\n",
    "            while pq:\n",
    "                w, node = heappop(pq)\n",
    "                if node not in d:\n",
    "                    d[node] = w + appleCost[node]\n",
    "                    for nei, weight in g[node]:\n",
    "                        heappush(pq, (w + weight * (k + 1), nei))\n",
    "            return min(d.values())\n",
    "        return [dijkstra(i) for i in range(n)]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, roads: List[List[int]], appleCost: List[int], k: int) -> List[int]:\n",
    "        def dijkstra(i):\n",
    "            pq, d, g = [(0, i)], defaultdict(int), defaultdict(list)\n",
    "            for u, v, w in roads:\n",
    "                g[u - 1].append((v - 1, w))\n",
    "                g[v - 1].append((u - 1, w))\n",
    "            while pq:\n",
    "                w, node = heappop(pq)\n",
    "                if node not in d:\n",
    "                    d[node] = w + appleCost[node]\n",
    "                    for nei, weight in g[node]:\n",
    "                        heappush(pq, (w + weight * (k + 1), nei))\n",
    "            return min(d.values())\n",
    "        return [dijkstra(i) for i in range(n)]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\r\n",
    "    def minCost(self, n: int, roads: List[List[int]], appleCost: List[int], k: int) -> List[int]:\r\n",
    "        g = collections.defaultdict(list)\r\n",
    "        for a, b, c in roads:\r\n",
    "            g[a - 1].append((b - 1, c * (k + 1)))\r\n",
    "            g[b - 1].append((a - 1, c * (k + 1)))\r\n",
    "        visit = [0] * n\r\n",
    "        pq = sorted((c, i) for i, c in enumerate(appleCost))\r\n",
    "        while pq:\r\n",
    "            c, u = heapq.heappop(pq)\r\n",
    "            if visit[u]:\r\n",
    "                continue\r\n",
    "            visit[u] = 1\r\n",
    "            for v, nc in g[u]:\r\n",
    "                if appleCost[v] > c + nc:\r\n",
    "                    appleCost[v] = c + nc\r\n",
    "                    heapq.heappush(pq, (appleCost[v], v))\r\n",
    "        return appleCost"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, roads: List[List[int]], appleCost: List[int], k: int) -> List[int]:\n",
    "        g = [[] for _ in range(n)]\n",
    "        for a, b, w in roads:\n",
    "            g[a - 1].append([b - 1, (k + 1) * w])\n",
    "            g[b - 1].append([a - 1, (k + 1) * w])\n",
    "        ans = [inf] * n \n",
    "\n",
    "        def dij(start):\n",
    "            dis = [inf] * n \n",
    "            h = [[start, 0]]\n",
    "            while h:\n",
    "                a, d = heappop(h)\n",
    "                if d >= dis[a]:\n",
    "                    continue\n",
    "                dis[a] = d \n",
    "                for nxt, delta in g[a]:\n",
    "                    if dis[nxt] > delta + dis[a]:\n",
    "                        heappush(h, [nxt, delta + dis[a]])\n",
    "            return dis \n",
    "        \n",
    "        for i in range(n):\n",
    "            dis = dij(i)\n",
    "            for j in range(n):\n",
    "                ans[j] = min(ans[j], dis[j] + appleCost[i])\n",
    "        return ans \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, roads: List[List[int]], appleCost: List[int], k: int) -> List[int]:\n",
    "        g = defaultdict(list)\n",
    "        for a, b, cost in roads:\n",
    "            g[a - 1].append([b - 1, cost])\n",
    "            g[b - 1].append([a - 1, cost])\n",
    "        \n",
    "        def dijkstra(start):\n",
    "            ans = inf\n",
    "            dist = [inf] * n\n",
    "            dist[start] = 0\n",
    "            q = [(0, start)]\n",
    "            while q:\n",
    "                cost, node = heapq.heappop(q)\n",
    "                ans = min(ans, cost * (k + 1) + appleCost[node])\n",
    "                # if dist[node] < cost:\n",
    "                #     continue\n",
    "                for nei, cost in g[node]:\n",
    "                    d = dist[node] + cost\n",
    "                    if d < dist[nei]:\n",
    "                        dist[nei] = d\n",
    "                        heapq.heappush(q, (d, nei))\n",
    "            return ans\n",
    "        return [dijkstra(i) for i in range(n)]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "import heapq as hq\n",
    "class Solution:\n",
    "    def minCost(self, n: int, roads: List[List[int]], appleCost: List[int], k: int) -> List[int]:\n",
    "        \n",
    "        ad=collections.defaultdict(list)\n",
    "\n",
    "        for s,e,v in roads:\n",
    "            ad[s].append([v,e])\n",
    "            ad[e].append([v,s])\n",
    "        ans=[]\n",
    "        for s in range(1,n+1):\n",
    "            dis={i:float(\"inf\") for i in range(1,n+1)}\n",
    "            dis[s]=0\n",
    "            heap=[]\n",
    "            hq.heappush(heap,[0,s])\n",
    "            vis=[0]*(n+1)\n",
    "            while heap:\n",
    "                d,cur=hq.heappop(heap)\n",
    "                if vis[cur]==1:\n",
    "                    continue\n",
    "                vis[cur]=1\n",
    "                for nexd,nex in ad[cur]:\n",
    "                    if vis[nex]==0:\n",
    "                        if d+nexd<dis[nex]:\n",
    "                            dis[nex]=d+nexd\n",
    "                            hq.heappush(heap,[d+nexd,nex])\n",
    "            mx=float(\"inf\")\n",
    "            for x in dis:\n",
    "                tmp=dis[x]+k*dis[x]+appleCost[x-1]\n",
    "                if tmp<mx:\n",
    "                    mx=tmp\n",
    "            ans.append(mx)\n",
    "        return ans\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self,n:int,roads:List[List[int]],appleCost:List[int],k:int):\n",
    "        INF=0x3f3f3f3f3f3f3f3f\n",
    "        adj=[[] for _ in range(0,n+1)]                    #邻接表\n",
    "        for i in range(0,len(roads)):      #遍历roads建立邻接表\n",
    "            a,b=roads[i][0],roads[i][1]     #<a,b>:w\n",
    "            w=(k+1)*roads[i][2]\n",
    "            adj[a].append([b,w])\n",
    "            adj[b].append([a,w])\n",
    "        for i in range(1,n+1):         #建超级源点的边\n",
    "            adj[0].append([i,appleCost[i-1]])\n",
    "            adj[i].append([0,appleCost[i-1]])\n",
    "        dist=[INF for _ in range(0,n+1)]\n",
    "        dist[0]=0\n",
    "        pqu=[]                          #定义小根堆pqu,元素为[length,vno]\n",
    "        heapq.heappush(pqu,[0,0])      #源点元素进队\n",
    "        while pqu:\n",
    "            e=heapq.heappop(pqu)        #出队元素e\n",
    "            u=e[1]                      #出队顶点u\n",
    "            for edj in adj[u]:\n",
    "                v,w=edj[0],edj[1]\n",
    "                if dist[v]>dist[u]+w:    #边松驰\n",
    "                    dist[v]=dist[u]+w\n",
    "                    heapq.heappush(pqu,[dist[v],v])      #顶点v元素进队\n",
    "        ans=[0]*n\n",
    "        for i in range(1,n+1):\n",
    "            ans[i-1]=dist[i]\n",
    "        return ans\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self,n:int,roads:List[List[int]],appleCost:List[int],k:int):\n",
    "        INF=0x3f3f3f3f3f3f3f3f\n",
    "        adj=[[] for _ in range(0,n+1)]                    #邻接表\n",
    "        for i in range(0,len(roads)):      #遍历roads建立邻接表\n",
    "            a,b=roads[i][0],roads[i][1]     #<a,b>:w\n",
    "            w=(k+1)*roads[i][2]\n",
    "            adj[a].append([b,w])\n",
    "            adj[b].append([a,w])\n",
    "        for i in range(1,n+1):         #建超级源点的边\n",
    "            adj[0].append([i,appleCost[i-1]])\n",
    "            adj[i].append([0,appleCost[i-1]])\n",
    "        dist=[INF for _ in range(0,n+1)]\n",
    "        dist[0]=0\n",
    "        pqu=[]                          #定义小根堆pqu,元素为[length,vno]\n",
    "        heapq.heappush(pqu,[0,0])      #源点元素进队\n",
    "        while pqu:\n",
    "            e=heapq.heappop(pqu)        #出队元素e\n",
    "            u=e[1]                      #出队顶点u\n",
    "            for edj in adj[u]:\n",
    "                v,w=edj[0],edj[1]\n",
    "                if dist[v]>dist[u]+w:    #边松驰\n",
    "                    dist[v]=dist[u]+w\n",
    "                    heapq.heappush(pqu,[dist[v],v])      #顶点v元素进队\n",
    "        ans=[0]*n\n",
    "        for i in range(1,n+1):\n",
    "            ans[i-1]=dist[i]\n",
    "        return ans\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "INF = int(1e18)\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, roads: List[List[int]], appleCost: List[int], k: int) -> List[int]:\n",
    "        START = n  # 虚拟源点\n",
    "        adjList = [[] for _ in range(n + 1)]\n",
    "        for u, v, w in roads:\n",
    "            u, v = u - 1, v - 1\n",
    "            adjList[u].append((v, w * (k + 1)))\n",
    "            adjList[v].append((u, w * (k + 1)))\n",
    "        for i in range(n):\n",
    "            adjList[START].append((i, appleCost[i]))\n",
    "            adjList[i].append((START, appleCost[i]))\n",
    "        dist = dijkstra(n + 1, adjList, START)\n",
    "        return dist[:-1]\n",
    "\n",
    "\n",
    "def dijkstra(n: int, adjList: Sequence[Sequence[Tuple[int, int]]], start: int) -> List[int]:\n",
    "    dist = [INF] * n\n",
    "    dist[start] = 0\n",
    "    pq = [(0, start)]\n",
    "\n",
    "    while pq:\n",
    "        curDist, cur = heappop(pq)\n",
    "        if dist[cur] < curDist:\n",
    "            continue\n",
    "        for next, weight in adjList[cur]:\n",
    "            cand = dist[cur] + weight\n",
    "            if cand < dist[next]:\n",
    "                dist[next] = cand\n",
    "                heappush(pq, (dist[next], next))\n",
    "    return dist"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self,n:int,roads:List[List[int]],appleCost:List[int],k:int):\n",
    "        INF=0x3f3f3f3f3f3f\n",
    "        adj=[[] for _ in range(0,n+1)]                    #邻接表\n",
    "        for i in range(0,len(roads)):      #遍历roads建立邻接表\n",
    "            a,b=roads[i][0],roads[i][1]     #<a,b>:w\n",
    "            w=(k+1)*roads[i][2]\n",
    "            adj[a].append([b,w])\n",
    "            adj[b].append([a,w])\n",
    "        for i in range(1,n+1):         #建超级源点的边\n",
    "            adj[0].append([i,appleCost[i-1]])\n",
    "            adj[i].append([0,appleCost[i-1]])\n",
    "        dist=[INF for _ in range(0,n+1)]\n",
    "        dist[0]=0\n",
    "        pqu=[]                          #定义小根堆pqu,元素为[length,vno]\n",
    "        heapq.heappush(pqu,[0,0])      #源点元素进队\n",
    "        while pqu:\n",
    "            e=heapq.heappop(pqu)        #出队元素e\n",
    "            u=e[1]                      #出队顶点u\n",
    "            for edj in adj[u]:\n",
    "                v,w=edj[0],edj[1]\n",
    "                if dist[v]>dist[u]+w:    #边松驰\n",
    "                    dist[v]=dist[u]+w\n",
    "                    heapq.heappush(pqu,[dist[v],v])      #顶点v元素进队\n",
    "        ans=[0]*n\n",
    "        for i in range(1,n+1):\n",
    "            ans[i-1]=dist[i]\n",
    "        return ans\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "import math\n",
    "from typing import List\n",
    "from collections import deque, defaultdict\n",
    "\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, roads: List[List[int]], appleCost: List[int], k: int) -> List[int]:\n",
    "        \"\"\"\n",
    "\n",
    "        :param n:\n",
    "        :param roads:\n",
    "        :param appleCost:\n",
    "        :param k:\n",
    "        :return:\n",
    "        \"\"\"\n",
    "        m1 ={}\n",
    "        for k1,v in enumerate(appleCost):\n",
    "            m1[k1+1] = v\n",
    "        m2 = defaultdict(list)\n",
    "        for i in roads:\n",
    "            m2[i[0]].append((i[1], i[2]))\n",
    "            m2[i[1]].append((i[0], i[2]))\n",
    "        minv = min(appleCost)\n",
    "        dq = deque()\n",
    "        for i in m1:\n",
    "\n",
    "            dq.append((i, m1[i]))\n",
    "        m3 = {}\n",
    "        while dq:\n",
    "            first, v1 = dq.popleft()\n",
    "            ref = min(v1, m1[first])\n",
    "            if first not in m3:\n",
    "                m3[first] = ref\n",
    "            else:\n",
    "                if m3[first] <= ref:\n",
    "                    continue\n",
    "                m3[first] = ref\n",
    "            for i in m2[first]:\n",
    "                vv = i\n",
    "                newp = vv[1] * (k+1)\n",
    "                dq.append((vv[0], ref + newp))\n",
    "        ret = []\n",
    "        for i in range(1, n+1):\n",
    "            ret.append(m3.get(i, m1.get(i)))\n",
    "        return ret\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "\n",
    "# 状压DP，dp[i][j]表示前i个左侧数已经根j所表示的二进制位的右侧的数匹配时，后续完成两组点连通的最小代价\n",
    "\n",
    "\n",
    "class Solution:\n",
    "    def connectTwoGroups(self, cost: List[List[int]]) -> int:\n",
    "\n",
    "        m,  n = len(cost), len(cost[0])\n",
    "        dp = [[-1] * (1 << n) for _ in range(m + 1)]\n",
    "\n",
    "        mask = (1 << n) - 1\n",
    "        minCostY = [10 ** 9] * n\n",
    "        # print(minCostY)\n",
    "        for row in cost:\n",
    "            for j, c in enumerate(row):\n",
    "                minCostY[j] = min(minCostY[j], c)\n",
    "\n",
    "        def dfs(i: int, choose: int) -> int:\n",
    "            # nonlocal dp\n",
    "            if dp[i][choose] >= 0:\n",
    "                return dp[i][choose]\n",
    "            if i == m:\n",
    "                oriChoose = choose\n",
    "                choose = (choose ^ mask) & mask\n",
    "                res = 0\n",
    "                while choose:\n",
    "                    # print(choose & (-choose))\n",
    "                    lst = (choose & (-choose)).bit_length() - 1\n",
    "                    # print(lst)\n",
    "                    res += minCostY[lst]\n",
    "                    choose &= (choose - 1)\n",
    "                dp[i][oriChoose] = res\n",
    "                return res\n",
    "            res = 10 ** 9\n",
    "            for j in range(n):\n",
    "                res = min(res,  cost[i][j] + dfs(i + 1, choose | (1 << j)))\n",
    "            dp[i][choose] = res\n",
    "            return res\n",
    "        ans = dfs(0, 0)\n",
    "        return ans\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def connectTwoGroups(self, cost: List[List[int]]) -> int:\n",
    "        ##矩阵每行每列都至少选一个坐标\n",
    "        n,m=len(cost),len(cost[0])\n",
    "        minCost=[min(col) for col in zip(*cost)]\n",
    "\n",
    "        @cache\n",
    "        def dfs(i,nodes):\n",
    "            if i<0:\n",
    "                return sum(c for k,c in enumerate(minCost) if nodes&(1<<k))\n",
    "            return min(dfs(i-1,nodes&~(1<<k))+c for k,c in enumerate(cost[i]))\n",
    "        return dfs(n-1,(1<<m)-1)\n",
    "            "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def connectTwoGroups(self, cost: List[List[int]]) -> int:\n",
    "        i = len(cost)\n",
    "        j = len(cost[0])\n",
    "\n",
    "        minCost = [min(i) for i in zip(*cost)]\n",
    "\n",
    "        @cache \n",
    "        def dp(i, rest):\n",
    "            if i < 0: return sum(c for k, c in enumerate(minCost) if rest >> k & 1)\n",
    "            \n",
    "            res = inf\n",
    "            for n in range(j):\n",
    "                res = min(res, dp(i - 1, rest & ~(1 << n)) + cost[i][n])\n",
    "            return res\n",
    "        \n",
    "        return dp(i - 1, (1 << j) - 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        cuts.sort()\n",
    "        m = len(cuts)\n",
    "        cuts = [0]+cuts+[n]\n",
    "        dp = [[0]*(m+2) for _ in range(m+2)]\n",
    "        \n",
    "        for i in range(m+1,-1,-1):\n",
    "            for j in range(i+2,m+2):\n",
    "                    minn = 10**9\n",
    "                    for k in range(i+1,j):\n",
    "                        minn = min(minn,dp[k][j]+dp[i][k])\n",
    "                    dp[i][j] = minn + cuts[j]-cuts[i]\n",
    "        return dp[0][m+1]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        m = len(cuts)\n",
    "        cuts.sort()\n",
    "        cuts = [0] + cuts + [n]\n",
    "        dp = [[0]*(m+2) for _ in range(m+2)]\n",
    "\n",
    "        for L in range(3, m+3):\n",
    "            for i in range(m+2-L+1):\n",
    "                l,r = i,i+L-1\n",
    "                dp[l][r] = float('inf')\n",
    "                for k in range(l+1,r):\n",
    "                    dp[l][r] = min(dp[l][r], dp[l][k]+dp[k][r])\n",
    "                dp[l][r] += (cuts[r] - cuts[l])\n",
    "        return dp[0][m+1]\n",
    "        pass"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        cuts = [0] + sorted(cuts) + [n]\n",
    "\n",
    "        len_ = len(cuts)\n",
    "        f = [[0] * len_ for _ in range(len_)]  # i 有n个状态, 又有i + 1, 所以大小为n + 1\n",
    "        for i in range(len_ - 3, -1, -1):\n",
    "            for j in range(i + 2, len_):\n",
    "                f[i][j] = min(f[i][k] + f[k][j] + cuts[j] - cuts[i] for k in range(i + 1, j))\n",
    "                # res = inf \n",
    "                # for k in range(i + 1, j):\n",
    "                #     cut = cuts[k]\n",
    "                #     res = min(res, f[i][k] + f[k][j] + cuts[j] - cuts[i])\n",
    "                # f[i][j] = res\n",
    "                \n",
    "        return f[0][-1]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        cuts = [0] + sorted(cuts) + [n]\n",
    "\n",
    "        len_ = len(cuts)\n",
    "        f = [[0] * len_ for _ in range(len_)]  # i 有n个状态, 又有i + 1, 所以大小为n + 1\n",
    "        for i in range(len_ - 3, -1, -1):\n",
    "            for j in range(i + 2, len_):\n",
    "                f[i][j] = min(f[i][k] + f[k][j] + cuts[j] - cuts[i] for k in range(i + 1, j))\n",
    "                # res = inf \n",
    "                # for k in range(i + 1, j):\n",
    "                #     cut = cuts[k]\n",
    "                #     res = min(res, f[i][k] + f[k][j] + cuts[j] - cuts[i])\n",
    "                # f[i][j] = res\n",
    "                \n",
    "        return f[0][-1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        cuts.sort()  \n",
    "        cuts.insert(0,0)\n",
    "        cuts.append(n)\n",
    "        m = len(cuts)\n",
    "        dp = [[0] * m for _ in range(m)]\n",
    "        for i in range(m - 1, -1, -1):\n",
    "            for j in range(i + 1, m):\n",
    "                dp[i][j] = (j - i) * (cuts[j] - cuts[i])\n",
    "                for k in range(i + 1, j):\n",
    "                    dp[i][j] = min(dp[i][j], dp[i][k] + dp[k][j] + cuts[j] - cuts[i])\n",
    "        \n",
    "        return dp[0][-1] - n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        cuts = [0] + sorted(cuts) + [n]\n",
    "\n",
    "        x = len(cuts)\n",
    "        f = [[0] * x for _ in range(x)]\n",
    "        for i in range(x - 3, -1, -1):\n",
    "            for j in range(i + 2, x):\n",
    "                res = inf\n",
    "                for k in range(i + 1, j):\n",
    "                    res = min(res, f[i][k] + f[k][j] + cuts[j] - cuts[i])\n",
    "                f[i][j] = res if res != inf else 0\n",
    "\n",
    "        return f[0][x - 1]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        cuts = [0] + sorted(cuts) + [n]\n",
    "        x = len(cuts)\n",
    "        f = [[0] * x for _ in range(x)]\n",
    "\n",
    "        for i in range(x - 3, -1, -1):\n",
    "            for j in range(i + 2, x):\n",
    "                res = inf\n",
    "                for k in range(i + 1, j):\n",
    "                    res = min(res, f[i][k] + f[k][j] + cuts[j] - cuts[i])\n",
    "                f[i][j] = res if res != inf else 0\n",
    "        return f[0][-1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        cuts.sort()\n",
    "        nums = [0] + cuts + [n]\n",
    "        n = len(nums)\n",
    "        dp = [[0] * n for _ in range(n)]\n",
    "\n",
    "        for i in range(n):\n",
    "            dp[i-1][i] = 0\n",
    "            for j in range(i-2, -1, -1):\n",
    "                best = math.inf\n",
    "                for k in range(j+1, i):\n",
    "                    best = min(best, dp[j][k] + dp[k][i])\n",
    "                dp[j][i] = best + nums[i] - nums[j]\n",
    "        return dp[0][-1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        m=len(cuts)\n",
    "        cuts.sort()\n",
    "        cuts.insert(0,0)\n",
    "        cuts.append(n)\n",
    "        m+=2\n",
    "        dp=[[-1]*m for i in range(m)]\n",
    "        def f(i,j):\n",
    "            if dp[i][j]!=-1:return dp[i][j]\n",
    "            if i==j-1:\n",
    "                dp[i][j]=0\n",
    "                return 0\n",
    "            fee=math.inf\n",
    "            for k in range(i+1,j):\n",
    "                fee=min(fee,f(i,k)+f(k,j)+cuts[j]-cuts[i])\n",
    "            dp[i][j]=fee\n",
    "            return fee \n",
    "        return f(0,m-1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        m = len(cuts)\n",
    "        cuts.sort()\n",
    "        arr = [0]*(m+2)\n",
    "        for i in range(m):\n",
    "            arr[i+1] = cuts[i]\n",
    "        arr[m+1] = n\n",
    "        def f(arr,l,r,dp):\n",
    "            if dp[l][r]!=-1:\n",
    "                return dp[l][r]\n",
    "            if l>r:\n",
    "                return 0\n",
    "            if l==r:\n",
    "                return arr[r+1]-arr[l-1]\n",
    "            ans = float('inf')\n",
    "            for k in range(l,r+1):\n",
    "                ans = min(ans,f(arr,l,k-1,dp)+f(arr,k+1,r,dp))\n",
    "            ans += arr[r+1]-arr[l-1]\n",
    "            dp[l][r] = ans\n",
    "            return ans\n",
    "        dp = [[-1]*(m+2) for _ in range(m+2)]\n",
    "        return f(arr,1,m,dp)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        cuts.sort()\n",
    "        arr = []\n",
    "        cuts = [0] + cuts + [n]\n",
    "        for x, y in pairwise(cuts):\n",
    "            arr.append(y - x)\n",
    "        print(arr)\n",
    "        m = len(arr)\n",
    "        pre = [0]\n",
    "        for x in arr: pre.append(pre[-1] + x)\n",
    "        print(pre)\n",
    "        # 区间dp\n",
    "        # 定义f[i][j]表示合并i-j的最小花费\n",
    "        # f[i]][j] = min(f[i][mid] + f[mid][j] + sum(arr[i:j+1]))\n",
    "        # f[i][i] = arr[i]\n",
    "        f = [[inf] * m for _ in range(m)]\n",
    "        for i in range(m): f[i][i] = 0\n",
    "        for i in range(m - 1, -1, -1):\n",
    "            for j in range(i + 1, m):\n",
    "                for mid in range(i, j):\n",
    "                    f[i][j] = min(f[i][j], f[i][mid] + f[mid + 1][j] + sum(arr[i: j + 1]))\n",
    "        print(f)\n",
    "        return f[0][m - 1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        cuts.sort()\n",
    "        blocks=[cuts[0]]\n",
    "        for i in range(len(cuts)-1):\n",
    "            blocks.append(cuts[i+1]-cuts[i])\n",
    "        blocks.append(n-cuts[-1])\n",
    "        m=len(blocks)\n",
    "        cost=[[0]*m for _ in range(m)]\n",
    "        dp=[[float('inf')]*m for _ in range(m)]\n",
    "        #dp[i][j] 表示将区间[i,j]的木棍合并为一根的最小费用\n",
    "        #dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+length(i,j))\n",
    "        for i in range(m):\n",
    "            cost[i][i]=blocks[i]\n",
    "            dp[i][i]=0\n",
    "        for i in range(m):\n",
    "            for j in range(i+1,m):\n",
    "                cost[i][j]=cost[i][j-1]+blocks[j]\n",
    "        \n",
    "        for len_ in range(2,m+1):\n",
    "            for l in range(m):\n",
    "                r=l+len_-1\n",
    "                if r>=m:continue\n",
    "                for k in range(l,r):\n",
    "                    dp[l][r]=min(dp[l][r],dp[l][k]+dp[k+1][r]+cost[l][r])\n",
    "        return dp[0][-1]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        # 先想暴力 基础case\n",
    "        cuts.sort()\n",
    "        # 每次选择一个分割点\n",
    "        @cache\n",
    "        def dfs(l, r):\n",
    "            if r - l < 2:\n",
    "                return 0\n",
    "            # 顶多转移是log的\n",
    "            index1 = bisect_right(cuts, l)\n",
    "            index2 = bisect_left(cuts, r)\n",
    "            if index1 >= index2:\n",
    "                return 0\n",
    "            res = inf\n",
    "            for k in cuts[index1:index2]:\n",
    "                cur = dfs(l, k) + dfs(k, r) + r - l\n",
    "                res = cur if cur < res else res\n",
    "            return res\n",
    "        \n",
    "\n",
    "        ans = dfs(0, n)\n",
    "        dfs.cache_clear()\n",
    "        return ans\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        cuts.sort()\n",
    "        cutdict = {x:ind for ind, x in enumerate(cuts)}\n",
    "        cutdict[0] = -1\n",
    "        cutdict[n] = len(cuts) \n",
    "        @lru_cache(None)\n",
    "        def myfun(st, ed):\n",
    "            ind_st, ind_ed = cutdict[st], cutdict[ed]\n",
    "            if ind_ed - ind_st == 1: return 0\n",
    "            b = float(\"inf\")\n",
    "            for i in range(ind_st+1, ind_ed):\n",
    "                a = myfun(st, cuts[i]) + myfun(cuts[i], ed)\n",
    "                b = min(a, b)\n",
    "            return (b + ed - st)\n",
    "        ans = myfun(0, n)\n",
    "        return ans"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        newcuts = [0] + sorted(cuts) + [n]\n",
    "        m = len(newcuts)\n",
    "        dp = [[0] * m for _ in range(m)]\n",
    "        \n",
    "        for i in range(m-3, -1, -1):\n",
    "            for j in range(i+2, m):\n",
    "                res = inf \n",
    "                for k in range(i+1, j):\n",
    "                    res = min(res, dp[i][k] + dp[k][j] + newcuts[j] - newcuts[i])\n",
    "                dp[i][j] = res \n",
    "        \n",
    "        print(dp)\n",
    "        return dp[0][m-1]\n",
    "\n",
    "        # @cache\n",
    "        # def dfs(i, j):\n",
    "        #     if i + 1 >= j:\n",
    "        #         return 0\n",
    "        #     res = inf\n",
    "        #     for k in range(i+1, j):\n",
    "        #         res = min(res, dfs(i, k) + dfs(k, j) + newcuts[j] - newcuts[i])\n",
    "        #     return res\n",
    "\n",
    "        # return dfs(0, len(newcuts) - 1)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        cuts.extend([0,n])\n",
    "        cuts.sort()\n",
    "        \n",
    "        @functools.lru_cache(None)\n",
    "        def dp(start,end):\n",
    "            res=[]\n",
    "            for idx in range(start+1,end): # 接下来的一刀切在cuts[idx]这个位置\n",
    "                res.append(dp(start,idx)+dp(idx,end))\n",
    "            return min(res)+cuts[end]-cuts[start] if res else 0\n",
    "        return dp(0,len(cuts)-1)\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        from functools import lru_cache\n",
    "        @lru_cache(None)\n",
    "        def search(l, r):\n",
    "            ret = float(\"inf\")\n",
    "            flag = False\n",
    "            for c in cuts:\n",
    "                if c > l and c < r:\n",
    "                    flag = True\n",
    "                    tmp = r - l + search(l, c) + search(c, r)\n",
    "                    ret = min(ret, tmp)\n",
    "            if not flag:\n",
    "                return 0\n",
    "            return ret\n",
    "        return search(0, n)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        cuts.append(0)\n",
    "        cuts.append(n)\n",
    "        cuts.sort()\n",
    "\n",
    "        @lru_cache(None)\n",
    "        def cut(i, j):  # 直接用arr(i, j)切割的最小和\n",
    "            if i > j - 2:\n",
    "                return 0\n",
    "            ans = float('inf')\n",
    "\n",
    "            for k in range(i + 1, j):  # 遍历切割点\n",
    "                ans = min(ans, cut(i, k) + cut(k, j) + cuts[j] - cuts[i])\n",
    "            return ans\n",
    "\n",
    "        return cut(0, len(cuts) - 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        arr = [0] + sorted(cuts) + [n]\n",
    "        @lru_cache(None)\n",
    "        def f(a, b):\n",
    "            if a == b - 1:\n",
    "                return 0\n",
    "            return min((f(a, i) + f(i, b)) for i in range(a + 1, b)) + arr[b] - arr[a]\n",
    "        return f(0, len(arr) - 1)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        s={}#加一个字典，保存子结果，动态规划\n",
    "        cuts.sort()\n",
    "        cuts=[0]+cuts+[n]\n",
    "        l=len(cuts)\n",
    "        '''\n",
    "        从函数需要的参数可以看出，原函数需要最一般的参数，而新的函数只需要开头结尾，\n",
    "        因为它都在cuts,n这种需要情况下计算，只计算一种特殊情况就有可以保存子结果的优势\n",
    "        '''\n",
    "        def helper(st,ed):\n",
    "            if (st,ed) in s:\n",
    "                return s[(st,ed)]#加入字典提高效率的关键：有的话立刻返回\n",
    "            if ed-st==1:\n",
    "                s[(st,ed)]=0 #子结果入字典\n",
    "                return 0\n",
    "            elif ed-st==2:\n",
    "                s[(st,ed)]=cuts[ed]-cuts[st] #子结果入字典\n",
    "                return cuts[ed]-cuts[st]\n",
    "            else:\n",
    "                temp=float('inf')\n",
    "                for i in range(st+1,ed):\n",
    "                    temp=min(temp,helper(st,i)+helper(i,ed))\n",
    "                temp=temp+cuts[ed]-cuts[st]\n",
    "                s[(st,ed)]=temp #子结果入字典\n",
    "                return temp\n",
    "        return helper(0,l-1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        cuts.sort()\n",
    "        cuts = [0] + cuts + [n]\n",
    "        n_cuts = len(cuts)\n",
    "        dp = {}\n",
    "        def search(l, r):\n",
    "            if l+1 == r:\n",
    "                return 0\n",
    "            res = 1e10\n",
    "            for i in range(l+1, r):\n",
    "                if (cuts[l], cuts[i]) not in dp:\n",
    "                    dp[(cuts[l], cuts[i])] = search(l, i)\n",
    "                if (cuts[i], cuts[r]) not in dp:\n",
    "                    dp[(cuts[i], cuts[r])] = search(i, r)\n",
    "                cost_left = dp[(cuts[l], cuts[i])]\n",
    "                cost_right = dp[(cuts[i], cuts[r])]\n",
    "                res = min(res, cost_left+cost_right)\n",
    "            return cuts[r] - cuts[l] + res\n",
    "        dp[(0,n)] = search(0, n_cuts-1)\n",
    "        return dp[(0,n)]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        A = [0] + sorted(cuts) + [n]\n",
    "        @lru_cache(None)\n",
    "        def dp(i,j):\n",
    "            if i+1>=j:\n",
    "                return 0\n",
    "            return A[j]-A[i] + min(dp(i,k) +dp(k,j) for k in range(i+1,j))\n",
    "        return dp(0,len(A)-1)\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        cuts.sort()\n",
    "        d={}\n",
    "        \n",
    "            \n",
    "        def cut(l,r,cuts):\n",
    "            if len(cuts)==0:\n",
    "                return 0\n",
    "            if len(cuts)==1:\n",
    "                return r-l\n",
    "            tmp=float('inf')\n",
    "            \n",
    "            for i in range(len(cuts)):\n",
    "                \n",
    "                \n",
    "                v1,v2=(l,cuts[i]),(cuts[i],r)\n",
    "                if v1 not in d:\n",
    "                    d[v1]=cut(l,cuts[i],cuts[:i])\n",
    "                if v2 not in d:\n",
    "                    d[v2]=cut(cuts[i],r,cuts[i+1:])\n",
    "                    \n",
    "                cur=d[v1]+d[v2]+r-l\n",
    "                \n",
    "                tmp=min(cur,tmp)\n",
    "            return tmp\n",
    "                \n",
    "                \n",
    "        return cut(0,n,cuts)\n",
    "        \n",
    "                "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        cuts.sort()\n",
    "        dp = {}\n",
    "        cuts.insert(0, 0)\n",
    "        cuts.append(n)\n",
    "\n",
    "        def find(i, j):\n",
    "            if (i, j) in dp:\n",
    "                return dp[(i, j)]\n",
    "            if i+1 >= j:\n",
    "                dp[(i, j)] = 0\n",
    "                return 0\n",
    "            \n",
    "            if j == i+2:\n",
    "                dp[(i, j)] = cuts[j] - cuts[i]\n",
    "                return dp[(i, j)]\n",
    "            \n",
    "            best = None\n",
    "            for x in range(i+1, j):\n",
    "                cur = find(i, x) + find(x, j) + cuts[j] - cuts[i]\n",
    "                if not best or cur < best:\n",
    "                    best = cur\n",
    "            \n",
    "            dp[(i, j)] = best\n",
    "            return best\n",
    "        \n",
    "        return find(0, len(cuts)-1)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "\n",
    "        m = len(cuts)\n",
    "        cuts.sort()\n",
    "        answerdict = {}\n",
    "        def _minCost(i, j):\n",
    "            if j - i == 1:\n",
    "                return 0\n",
    "            if (i, j) in answerdict:\n",
    "                return answerdict[(i, j)]\n",
    "            if i == -1:\n",
    "                l = 0\n",
    "            else:\n",
    "                l = cuts[i]\n",
    "            if j == m:\n",
    "                r = n\n",
    "            else:\n",
    "                r = cuts[j]\n",
    "    \n",
    "            answer = min([_minCost(i, k)+_minCost(k, j) for k in range(i+1, j)]) + r - l\n",
    "            answerdict[(i, j)] = answer\n",
    "            return answer\n",
    "        \n",
    "        return _minCost(-1, m)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, m: int, nums: List[int]) -> int:\n",
    "        n = len(nums)\n",
    "        nums = sorted(nums)\n",
    "        DP = [[10 ** 9 for _ in range(n)] for _ in range(n)]\n",
    "        def solve(l: int, r: int) -> int:\n",
    "            if l > r: return 0\n",
    "            x = nums[l - 1] if l > 0 else 0\n",
    "            y = nums[r + 1] if r < n - 1 else m\n",
    "            if l == r: return y - x\n",
    "            if DP[l][r] != 10 ** 9: return DP[l][r]\n",
    "            for i in range(l, r + 1):\n",
    "                DP[l][r] = min(DP[l][r],\n",
    "                        y - x + solve(l, i - 1) + solve(i + 1, r))\n",
    "            return DP[l][r]\n",
    "        return solve(0, n - 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        cuts.sort()\n",
    "\n",
    "        @lru_cache(None)\n",
    "        def cut(l, r, i, j):  # 在(l,r)直接用arr[i, j]切割的最小和\n",
    "            if i > j:\n",
    "                return 0\n",
    "            elif i == j:\n",
    "                return r - l\n",
    "            ans = n * (j - i + 1)\n",
    "            for k in range(i, j + 1):  # 遍历切割点\n",
    "                ans = min(ans, cut(l, cuts[k], i, k - 1) + cut(cuts[k], r, k + 1, j) + r - l)\n",
    "            return ans\n",
    "\n",
    "        return cut(0, n, 0, len(cuts) - 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "import functools\n",
    "class Solution:\n",
    "    \n",
    "    def minCost(self, lens: int, cuts: List[int]) -> int:\n",
    "        cuts.sort()\n",
    "        @lru_cache(None)\n",
    "        def dfs(head,tail,l,r):\n",
    "            # print(head,tail,l,r)\n",
    "            if l>=r:\n",
    "                return 0\n",
    "            if l+1==r:\n",
    "                return tail-head\n",
    "            res=2**31-1\n",
    "            \n",
    "            for i in range(l,r):\n",
    "                res=min(res,tail-head+dfs(head,cuts[i],l,i)+dfs(cuts[i],tail,i+1,r))\n",
    "            return res\n",
    "        \n",
    "        return dfs(0,lens,0,len(cuts))\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        cuts = [0] + sorted(cuts) + [n]\n",
    "        memo = {}\n",
    "        for i in range(1, len(cuts)):\n",
    "            memo[(cuts[i-1], cuts[i])] = cuts[i] - cuts[i-1]\n",
    "        def dp(i, j):\n",
    "            if (i, j) in memo:\n",
    "                return memo[(i, j)]\n",
    "            ans = float(\"inf\")\n",
    "            for k in cuts:\n",
    "                if i < k < j:\n",
    "                    ans = min(ans, dp(i, k) + dp(k, j) + j - i)\n",
    "            memo[(i, j)] = ans\n",
    "            return memo[(i, j)]\n",
    "        return dp(0, n) - n\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        cuts.sort()\n",
    "\n",
    "        @lru_cache(None)\n",
    "        def cut(l, r, i, j):  # 在(l,r)直接用arr[i, j]切割的最小和\n",
    "            if i > j:\n",
    "                return 0\n",
    "            elif i == j:\n",
    "                return r - l\n",
    "            ans = n * (j - i + 1)\n",
    "            for k in range(i, j + 1):  # 遍历切割点\n",
    "                ans = min(ans, cut(l, cuts[k], i, k - 1) + cut(cuts[k], r, k + 1, j) + r - l)\n",
    "            return ans\n",
    "\n",
    "        return cut(0, n, 0, len(cuts) - 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from functools import lru_cache\n",
    "import json\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts) -> int:\n",
    "        cuts=sorted(cuts)\n",
    "        @lru_cache(None)\n",
    "        def dp(l,r):\n",
    "            tmpcuts=[]\n",
    "            for c in cuts:\n",
    "                if c>l and c<r:\n",
    "                    tmpcuts.append(c)\n",
    "            if tmpcuts == []:\n",
    "                return 0\n",
    "            mincost=float('inf')\n",
    "            for idx,c in enumerate(tmpcuts):\n",
    "                mincost=min(mincost,dp(l,c)+dp(c,r))\n",
    "            return mincost+r-l\n",
    "            \n",
    "        return dp(0,n)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        arr = [0] + sorted(cuts) + [n]\n",
    "        dic={}\n",
    "        def f(a, b):\n",
    "            if a == b - 1:\n",
    "                dic[(a,b)]=0\n",
    "                return 0\n",
    "            elif (a,b) in dic:\n",
    "                return dic[(a,b)]\n",
    "            dic[(a,b)]=min((f(a, i) + f(i, b)) for i in range(a + 1, b)) + arr[b] - arr[a]\n",
    "            return dic[(a,b)]\n",
    "        return f(0, len(arr) - 1)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        cuts = sorted(cuts)\n",
    "        hashset = set(cuts)\n",
    "        cuts = [0] + cuts + [n]\n",
    "        hashmap = dict(zip(cuts, range(len(cuts))))\n",
    "        @lru_cache(None)\n",
    "        def solve(start, end):\n",
    "            cuts_ = cuts[hashmap[start]+1: hashmap[end]]\n",
    "            if len(cuts_) == 0: return 0\n",
    "            elif len(cuts_) == 1: return end - start\n",
    "            ans = float('inf')\n",
    "            for cutpoint in cuts_:\n",
    "                left = solve(start, cutpoint)\n",
    "                right = solve(cutpoint, end)\n",
    "                ans = min(ans, end - start + left + right)\n",
    "            return ans \n",
    "        return solve(0, n)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        cuts.sort()\n",
    "        rod = [0]+cuts+[n]\n",
    "\n",
    "        @lru_cache(None)\n",
    "        def cut_rod(left,right):\n",
    "            if rod.index(right)-rod.index(left)<=1 :\n",
    "                return 0\n",
    "            res = float(\"inf\")\n",
    "            for i in cuts[rod.index(left):rod.index(right)]:\n",
    "                total = right-left\n",
    "                if left<i<right:\n",
    "                    #flag = true\n",
    "                    total += cut_rod(left,i)+cut_rod(i,right)\n",
    "                    res = min(res,total)\n",
    "            return res\n",
    "        return cut_rod(0,n)\n",
    "\n",
    "        # m = len(cuts)\n",
    "        # cuts = [0] + sorted(cuts) + [n]\n",
    "        # f = [[0] * (m + 2) for _ in range(m + 2)]\n",
    "\n",
    "        # for i in range(m, 0, -1):\n",
    "        #     for j in range(i, m + 1):\n",
    "        #         f[i][j] = 0 if i == j else \\\n",
    "        #             min(f[i][k - 1] + f[k + 1][j] for k in range(i, j + 1))\n",
    "        #         f[i][j] += cuts[j + 1] - cuts[i - 1]\n",
    "        \n",
    "        # return f[1][m]\n",
    "\n",
    "\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        cuts.sort()\n",
    "        cuts = list(chain([0], cuts, [n]))\n",
    "        cache = {}\n",
    "        inf = float('inf')\n",
    "        def recur(i, j):\n",
    "            if j <= i + 1: return 0\n",
    "            key = (i, j)\n",
    "            cached = cache.get(key)\n",
    "            if cached is not None: return cached\n",
    "            result = inf\n",
    "            for k in range(i+1, j):\n",
    "                result = min(result, recur(i, k)+recur(k, j))\n",
    "            result += cuts[j] - cuts[i]\n",
    "            cache[key] = result\n",
    "            return result\n",
    "        return recur(0, len(cuts)-1)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        def dfs(cuts,i,j):\n",
    "            if  (i,j) in memo:\n",
    "                return memo[(i,j)]\n",
    "            if (j-i == 1):\n",
    "                return 0\n",
    "            ret = float('inf')\n",
    "            for k in range(i+1,j):\n",
    "                ret = min(ret, dfs(cuts,i,k)+dfs(cuts,k,j)+cuts[j]-cuts[i])\n",
    "            memo[(i,j)] = ret\n",
    "            return ret\n",
    "        memo = {}\n",
    "        cuts.sort()\n",
    "        cuts = [0] + cuts + [n]\n",
    "        return dfs(cuts,0,len(cuts)-1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        D={}\n",
    "        def DP(i,j,cuts):\n",
    "            if (i,j) in D: return D[(i,j)]\n",
    "            if j-i<=1: \n",
    "                D[(i,j)]=0\n",
    "                return D[(i,j)]\n",
    "            cc=[]\n",
    "            for x in cuts:\n",
    "                if x>i and x<j:\n",
    "                    cc.append(x)\n",
    "            if len(cc)==0: \n",
    "                D[(i,j)]=0\n",
    "                return D[(i,j)]\n",
    "            v=math.inf\n",
    "            for k in range(len(cc)):\n",
    "                v=min(v,DP(i,cc[k],cuts)+DP(cc[k],j,cuts)+j-i)\n",
    "            D[(i,j)]=v\n",
    "            return v\n",
    "        return DP(0,n,cuts)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        from functools import lru_cache\n",
    "        @lru_cache(None)\n",
    "        def dfs(l,r):\n",
    "            if l+1 == r:\n",
    "                return 0\n",
    "            res = float('inf')\n",
    "            for i in range(l+1,r):\n",
    "                res =min(res,dfs(l,i)+dfs(i,r)+cuts[r]-cuts[l])\n",
    "            return res\n",
    "        cuts += [0,n]\n",
    "        cuts.sort()\n",
    "        return dfs(0,len(cuts)-1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        @lru_cache(None)\n",
    "        def dfs(i:int,j:int)->int:\n",
    "            if i == j -1:\n",
    "                return 0\n",
    "            base = cuts[j]-cuts[i] #现长度\n",
    "            result = 2**32\n",
    "            for k in range(i+1,j):\n",
    "                result = min(dfs(i,k)+dfs(k,j),result)\n",
    "            return result+base\n",
    "        cuts += [0,n]\n",
    "        cuts.sort()\n",
    "        # print(cuts)\n",
    "        return dfs(0,len(cuts)-1)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        cuts.extend([0,n])\n",
    "        cuts.sort()\n",
    "        \n",
    "        @functools.lru_cache(None)\n",
    "        def dp(start,end):\n",
    "            res=[]\n",
    "            for idx in range(start+1,end): # 接下来的一刀切在cuts[idx]这个位置\n",
    "                res.append(dp(start,idx)+dp(idx,end))\n",
    "            return min(res)+cuts[end]-cuts[start] if res else 0\n",
    "        return dp(0,len(cuts)-1)\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        cuts.extend([0,n])\n",
    "        cuts.sort()\n",
    "        lenCuts = len(cuts)\n",
    "        @cache\n",
    "        def dp(i,j):\n",
    "            if j-i<=1: return 0\n",
    "            res = float(\"inf\")\n",
    "            for m in range(i+1,j):\n",
    "                res = min(res,dp(i,m)+dp(m,j))\n",
    "            return res+cuts[j]-cuts[i]\n",
    "        return dp(0,lenCuts-1)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        cuts.extend([0,n])\n",
    "        cuts.sort()\n",
    "        lenCuts = len(cuts)\n",
    "        @cache\n",
    "        def dp(i,j):\n",
    "            if j-i<=1: return 0\n",
    "            res = float(\"inf\")\n",
    "            for m in range(i+1,j):\n",
    "                res = min(res,dp(i,m)+dp(m,j))\n",
    "            return res+cuts[j]-cuts[i]\n",
    "        return dp(0,lenCuts-1)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from functools import lru_cache\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "\n",
    "        array = sorted([0] + cuts + [n])\n",
    "        \n",
    "        @lru_cache(None)\n",
    "        def compute(left, right):\n",
    "\n",
    "            if left == right - 1:\n",
    "                return 0\n",
    "\n",
    "            res = float('inf')\n",
    "            for mid in range(left + 1, right):\n",
    "                res = min(res, compute(left, mid) + compute(mid, right))\n",
    "\n",
    "            return res + array[right] - array[left]\n",
    "\n",
    "        return compute(0, len(array) - 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        cuts.sort()\n",
    "        cuts = [0] + cuts +[n]\n",
    "        memo = {}\n",
    "        k = len(cuts)\n",
    "        def walk(start,end):\n",
    "            if (start,end) in memo:\n",
    "                return memo[(start,end)]\n",
    "            if end - start == 1:\n",
    "                memo[(end,start)] = 0\n",
    "                return 0\n",
    "            if end - start == 2:\n",
    "                memo[(start,end)] = cuts[end] - cuts[start]\n",
    "                return cuts[end] - cuts[start]\n",
    "            temp = float('inf')\n",
    "            for i in range(start+1,end):\n",
    "                temp = min(temp,walk(start,i)+walk(i,end))\n",
    "            temp += cuts[end] - cuts[start]\n",
    "            memo[(start,end)] = temp\n",
    "            return temp\n",
    "        return walk(0,k-1)\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        @cache\n",
    "        def solve(i, j):\n",
    "            if i + 1 >= j:\n",
    "                return 0\n",
    "            ans = float('inf')\n",
    "            for k in range(i + 1, j):\n",
    "                ans = min(ans, cuts[j] - cuts[i] + solve(i, k) + solve(k, j))\n",
    "            return ans\n",
    "\n",
    "        cuts.append(0)\n",
    "        cuts.append(n)\n",
    "        cuts.sort()\n",
    "        return solve(0, len(cuts) - 1)\n",
    "\n",
    "        \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        # 需要切开的位置在数组中,假设切开k\n",
    "        # 左边为l,右边记为r\n",
    "        # j为要切割处\n",
    "        if len(cuts) == 1:\n",
    "            return n\n",
    "        cuts.sort()\n",
    "        cuts = [0] + cuts + [n] # 添加首尾,变成把cuts划分为长短为2的对的最小成本\n",
    "        _len = len(cuts)\n",
    "        @lru_cache(None)\n",
    "        def dfs(l,r):\n",
    "            if l+1 == r:\n",
    "                return 0\n",
    "            elif l+2 == r: # 只用砍一刀\n",
    "                return cuts[r] - cuts[l]\n",
    "            res = inf\n",
    "            t = cuts[r]-cuts[l]\n",
    "            for i in range(l+1,r):\n",
    "                res = min(dfs(i,r)+dfs(l,i),res)\n",
    "            return res+t\n",
    "        return dfs(0,_len-1)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        @cache\n",
    "        def dfs(i,j,l,r):\n",
    "            if i==j:return 0 \n",
    "            ans=10**9\n",
    "            for k in range(i,j):\n",
    "                ans=min(ans,dfs(i,k,l,cuts[k])+dfs(k+1,j,cuts[k],r)+r-l)\n",
    "            return ans\n",
    "        cuts.sort()\n",
    "        return dfs(0,len(cuts),0,n)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        cuts.sort()\n",
    "        m = len(cuts)\n",
    "\n",
    "        @cache\n",
    "        def dfs(l, r, cl, cr):\n",
    "            if cl > cr:\n",
    "                return 0\n",
    "            if cl == cr:\n",
    "                return r - l\n",
    "\n",
    "            ans = inf\n",
    "            for k in range(cl, cr+1):\n",
    "                ans = min(ans, dfs(l, cuts[k], cl, k-1) + dfs(cuts[k], r, k+1, cr))\n",
    "            return ans + r - l\n",
    "\n",
    "        return dfs(0, n, 0, m - 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        @cache\n",
    "        def dfs(i,j,l,r):\n",
    "            if i==j:return 0 \n",
    "            ans=10**9\n",
    "            for k in range(i,j):\n",
    "                ans=min(ans,dfs(i,k,l,cuts[k])+dfs(k+1,j,cuts[k],r)+r-l)\n",
    "            return ans\n",
    "        cuts.sort()\n",
    "        return dfs(0,len(cuts),0,n)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        @cache\n",
    "        def dfs(i,j,l,r):\n",
    "            if i==j:return 0 \n",
    "            ans=10**9\n",
    "            for k in range(i,j):\n",
    "                ans=min(ans,dfs(i,k,l,cuts[k])+dfs(k+1,j,cuts[k],r)+r-l)\n",
    "            return ans\n",
    "        cuts.sort()\n",
    "        return dfs(0,len(cuts),0,n)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        cuts.sort()\n",
    "        @cache\n",
    "        def f(l,r,ll,rr):\n",
    "            if ll > rr:\n",
    "                return 0\n",
    "            k = r-l\n",
    "            ans = inf\n",
    "            for i in range(ll, rr+1):\n",
    "                t = cuts[i]\n",
    "                ans = min(ans, k + f(l, t, ll, i-1) + f(t, r, i+1, rr))\n",
    "            return ans\n",
    "        return f(0, n, 0, len(cuts)-1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        cuts.sort()\n",
    "        return (f := cache(lambda l, r: min((r - l + f(l, c) + f(c, r) for c in cuts[bisect_right(cuts, l):bisect_left(cuts, r)]), default = 0)))(0, n)\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        @cache\n",
    "        def dfs(i,j):\n",
    "            if j-i==1:\n",
    "                return 0\n",
    "            res=[]\n",
    "            for k in range(len(cuts)):\n",
    "                if i<cuts[k]<j:\n",
    "                    res.append(dfs(i,cuts[k])+dfs(cuts[k],j)+j-i)\n",
    "            if res==[]:\n",
    "                return 0\n",
    "            return min(res)\n",
    "        return dfs(0,n)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from typing import *\n",
    "from math import *\n",
    "from functools import cache,lru_cache\n",
    "from queue import *\n",
    "from heapq import *\n",
    "from itertools import *\n",
    "from bisect import bisect_left\n",
    "# start-----------------------------------------------------\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        \n",
    "        @lru_cache(None)\n",
    "        def f(s,e):\n",
    "            res = inf\n",
    "            for x in cuts:\n",
    "                if s < x < e:\n",
    "                    res = min(res, e - s + f(s, x) + f(x, e))\n",
    "            if res == inf:\n",
    "                return 0\n",
    "            return res\n",
    "        return f(0, n)\n",
    "# end-------------------------------------------------------\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        cuts.sort()\n",
    "        fcuts = [0]\n",
    "        fcuts.extend(cuts)\n",
    "        fcuts.append(n)\n",
    "\n",
    "        @cache\n",
    "        def dfs(i, j):\n",
    "            if i + 1 == j:\n",
    "                return 0\n",
    "            if i + 2 == j:\n",
    "                return fcuts[j] - fcuts[i]\n",
    "            return min(dfs(i, m) + dfs(m, j) + fcuts[j] - fcuts[i] for m in range(i + 1, j))\n",
    "        \n",
    "        return dfs(0, len(fcuts) - 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts) -> int:\n",
    "        # 定义递归函数，i和j表示当前区间的左右端点\n",
    "        @cache\n",
    "        def dfs(i:int,j:int)->int:\n",
    "            # 边界条件：当区间长度小于等于1时，不需要再切割，返回0\n",
    "            if i+1>=j:\n",
    "                return 0\n",
    "            res = inf \n",
    "            # 枚举所有可能的切割点\n",
    "            for cut in cuts:\n",
    "                if i < cut < j:\n",
    "                    # 递归计算左右两个子区间的最小代价，并更新最小值\n",
    "                    res = min(res, dfs(i, cut) + dfs(cut, j) )\n",
    "            # 返回当前区间的最小代价，加上当前区间的长度\n",
    "            return res + j - i if res != inf else 0\n",
    "        # 调用递归函数，计算整个区间【0,n】的最小代价\n",
    "        return dfs(0,n)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        # @cache\n",
    "        # def dfs(i,j):\n",
    "        #     if i + 1 >= j:\n",
    "        #         return 0\n",
    "        #     res = inf\n",
    "        #     for cut in cuts:\n",
    "        #         if i < cut < j:\n",
    "        #             res = min(res, dfs(i,cut) + dfs(cut,j) + j - i)\n",
    "        #     return res if res != inf else 0\n",
    "        # return dfs(0,n)\n",
    "\n",
    "        cuts = [0] + sorted(cuts) + [n]\n",
    "        @cache\n",
    "        def dfs(i,j):\n",
    "            if i + 1 >= j:\n",
    "                return 0\n",
    "            res = inf \n",
    "            for k in range(i+1,j):\n",
    "                 res = min(res, dfs(i,k) + dfs(k,j) + cuts[j] - cuts[i])\n",
    "            return res\n",
    "        return dfs(0,len(cuts) - 1)\n",
    "\n",
    "        # f = [[0] * (n+1) for _ in range(n+1)]\n",
    "        # for i in range(n-1,-1,-1):\n",
    "        #     for j in range(i+2,n+1):\n",
    "        #         res = inf\n",
    "        #         for cut in cuts:\n",
    "        #             if i < cut < j:\n",
    "        #                 res = min(res,f[i][cut] + f[cut][j] + j - i)\n",
    "        #         f[i][j] = res if res != inf else 0\n",
    "        # return f[0][n]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        cuts.sort()\n",
    "        d = [0] + cuts + [n]\n",
    "        \n",
    "        @lru_cache(None)\n",
    "        def dfs(l,r):\n",
    "            if r == l + 1:\n",
    "                return 0\n",
    "            t = inf\n",
    "            for i in range(l+1,r):\n",
    "                t = min(t, dfs(l,i)+dfs(i,r))\n",
    "            return t + d[r] - d[l]\n",
    "        return dfs(0, len(d) - 1)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        m = len(cuts)\n",
    "        cuts.sort()\n",
    "        arr = [0] + cuts + [n]\n",
    "        @cache\n",
    "        def dfs(l, r):\n",
    "            if l > r:\n",
    "                return 0\n",
    "            if l == r:\n",
    "                return arr[r + 1] - arr[l - 1]\n",
    "            ans = inf\n",
    "            for k in range(l, r + 1):\n",
    "                ans = min(ans, dfs(l, k - 1) + dfs(k + 1, r) + arr[r + 1] - arr[l - 1])\n",
    "            return ans\n",
    "        return dfs(1, m)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        m = len(cuts)\n",
    "        cuts.sort()\n",
    "        arr = [0] + cuts + [n]\n",
    "        @cache\n",
    "        def dfs(l, r):\n",
    "            if l > r:\n",
    "                return 0\n",
    "            if l == r:\n",
    "                return arr[r + 1] - arr[l - 1]\n",
    "            ans = inf\n",
    "            for k in range(l, r + 1):\n",
    "                ans = min(ans, dfs(l, k - 1) + dfs(k + 1, r))\n",
    "            return ans + arr[r + 1] - arr[l - 1]\n",
    "        return dfs(1, m)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        m = len(cuts)\n",
    "        cuts.sort()\n",
    "        arr = [0] + cuts + [n]\n",
    "        @cache\n",
    "        def dfs(l, r):\n",
    "            if l > r:\n",
    "                return 0\n",
    "            if l == r:\n",
    "                return arr[r + 1] - arr[l - 1]\n",
    "            ans = inf\n",
    "            for k in range(l, r + 1):\n",
    "                ans = min(ans, dfs(l, k - 1) + dfs(k + 1, r) + arr[r + 1] - arr[l - 1])\n",
    "            return ans\n",
    "        return dfs(1, m)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "\n",
    "        cuts = [0] + sorted(cuts) + [n]\n",
    "\n",
    "        @cache\n",
    "        def dfs(left: int, right: int) -> int:\n",
    "            if left + 1 == right:\n",
    "                return 0\n",
    "            res = inf\n",
    "            for c in range(left + 1, right):\n",
    "                res = min(res, dfs(left, c) + dfs(c, right) + cuts[right] - cuts[left])\n",
    "            return res if res != inf else 0\n",
    "\n",
    "        return dfs(0, len(cuts) - 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        m = len(cuts)\n",
    "        cuts.sort()\n",
    "        cuts= [0] +cuts + [n]\n",
    "        @cache\n",
    "        def f(i,j):\n",
    "            if i>j:\n",
    "                return 0\n",
    "            res = inf\n",
    "            for k in range(i,j+1):    \n",
    "                res = min(res,f(i,k-1) + f(k+1,j) + cuts[j+1]-cuts[i-1])\n",
    "            return res\n",
    "        return f(1,m)\n",
    "                "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        @cache\n",
    "        def dfs(i, j):\n",
    "            if i >= j:\n",
    "                return 0\n",
    "            res = inf\n",
    "            for x in cuts:\n",
    "                if i < x < j:\n",
    "                    res = min(dfs(i, x) + dfs(x, j) + j - i, res)\n",
    "            if res == inf:\n",
    "                res = 0\n",
    "            # print(i, j, res)\n",
    "            return res\n",
    "        return dfs(0, n)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        cuts.sort()\n",
    "        @cache\n",
    "        def helper(i, j): # i,j之间去切，最小开销\n",
    "            if i+1==j: # 无需切割 \n",
    "                return 0\n",
    "            ans = inf\n",
    "            for k in cuts:\n",
    "                if i<k<j:\n",
    "                    ans = min(ans, helper(i, k)+helper(k, j)+j-i)\n",
    "            return ans if ans!=inf else 0\n",
    "        return helper(0, n)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        @functools.cache\n",
    "        def dfs(i, j):\n",
    "            if i + 1 > j:\n",
    "                return 0\n",
    "            res = inf\n",
    "            for c in cuts:\n",
    "                if i < c < j:\n",
    "                    res = min(res, dfs(i, c) + dfs(c, j) + (j - i))\n",
    "            return res if res != inf else 0\n",
    "\n",
    "        return dfs(0, n)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        cuts.append(0)\n",
    "        cuts.append(n)\n",
    "        cuts.sort()\n",
    "\n",
    "        @cache\n",
    "        def dfs(l, r):\n",
    "            if l + 1 == r:\n",
    "                return 0\n",
    "            return min(dfs(l, i) + dfs(i, r) for i in range(l+1, r)) + cuts[r] - cuts[l]\n",
    "\n",
    "        return dfs(0, len(cuts)-1)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        @cache\n",
    "        def dfs(i,j):\n",
    "            if i >= j-1:\n",
    "                return 0\n",
    "            cost = inf\n",
    "            for x in cuts:\n",
    "                if i<x<j:\n",
    "                    cost = min(cost,dfs(i,x) + dfs(x,j) + j-i) # 不需要记录路径则不需要pop\n",
    "            return cost if cost!=inf else 0\n",
    "        return dfs(0,n)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        @cache\n",
    "        def dfs(i, j):\n",
    "            if i + 1 >= j:\n",
    "                return 0\n",
    "            res = inf \n",
    "            for cut in cuts:\n",
    "                if i < cut < j:\n",
    "                    res = min(res, dfs(i, cut) + dfs(cut, j) + j - i)\n",
    "            return res if res != inf else 0\n",
    "        return dfs(0, n)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "\n",
    "        @cache\n",
    "        def dfs(left: int, right: int) -> int:\n",
    "            if left + 1 == right:\n",
    "                return 0\n",
    "            res = inf\n",
    "            for c in cuts:\n",
    "                if left < c < right:\n",
    "                    res = min(res, dfs(left, c) + dfs(c, right) + right - left)\n",
    "            return res if res != inf else 0\n",
    "\n",
    "        return dfs(0, n)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\r\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\r\n",
    "        cuts.sort()\r\n",
    "        # 定义函数dfs(l, r): 表示将存在于区间[l, r]内的所有cuts中的元素完成切割\r\n",
    "        # 的最小花费，由于cuts所有元素均在[0, n]中，所以dfs(0, n)为最终答案\r\n",
    "        @cache\r\n",
    "        def dfs(l, r):\r\n",
    "            # 使用二分找到cuts中存在于区间[l, r]的元素范围\r\n",
    "            lo, hi = bisect_right(cuts, l), bisect_left(cuts, r)\r\n",
    "            # 若上下界相等则意味着区间[l, r]中不包含cuts中的任何元素\r\n",
    "            if lo == hi: return 0\r\n",
    "            # 计算本次花费\r\n",
    "            cost = r - l\r\n",
    "            # 枚举所有分割点，计算所有分割方案产生的花费，从中取得最小值即可\r\n",
    "            return cost + min(dfs(l, c) + dfs(c, r) for c in cuts[lo:hi])\r\n",
    "        return dfs(0, n)\r\n",
    "        \r\n",
    "    # \r\n",
    "    def minCost2(self, n: int, cuts: List[int]) -> int:\r\n",
    "        cuts.sort()\r\n",
    "        f = cache(lambda l, r: min((r - l + f(l, c) + f(c, r) for c in cuts[bisect_right(cuts, l):bisect_left(cuts, r)]), default = 0))\r\n",
    "        return f(0, n)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        cuts.sort()\n",
    "        @lru_cache(None)\n",
    "        def dfs(l,r):\n",
    "            left , right = bisect.bisect_right(cuts,l) , bisect.bisect_left(cuts,r)\n",
    "            if left == right:return 0\n",
    "            cost = r - l\n",
    "            return cost + min(dfs(l,k) + dfs(k,r) for k in cuts[left:right])\n",
    "\n",
    "        return dfs(0,n)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        cuts.sort()\n",
    "        # 定义函数dp(l, r): 表示将存在于区间[l, r]内的所有cuts中的元素完成切割的最小花费，由于cuts所有元素均在[0, n]中，所以dfs(0, n)为最终答案\n",
    "        @cache\n",
    "        def dp(i, j):\n",
    "            # 使用二分找到cuts中存在于区间[l, r]的元素范围\n",
    "            left, right = bisect_right(cuts, i), bisect_left(cuts, j)\n",
    "            # 若上下界相等则意味着区间[l, r]中不包含cuts中的任何元素\n",
    "            if left == right:\n",
    "                return 0\n",
    "            # 计算本次花费\n",
    "            cost = j - i\n",
    "            # 枚举所有分割点，计算所有分割方案产生的花费，从中取得最小值即可            \n",
    "            return cost + min(dp(i, cut) + dp(cut, j) for cut in cuts[left: right])\n",
    "        return dp(0, n)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, n: int, cuts: List[int]) -> int:\n",
    "        cuts.sort()\n",
    "        cuts = [0] + cuts + [n]\n",
    "        m = len(cuts)\n",
    "        dic = {}\n",
    "        def dfs(i,j):\n",
    "            if (i,j) in dic:\n",
    "                return dic[(i,j)]\n",
    "            if i+1==j:\n",
    "                return 0\n",
    "            elif i+2==j:\n",
    "                ans = cuts[j]-cuts[i]\n",
    "                dic[(i,j)] = ans\n",
    "                return ans\n",
    "            ans = 1e7\n",
    "            for k in range(i+1,j):\n",
    "                ans = min(ans,dfs(i,k)+dfs(k,j)+cuts[j]-cuts[i])\n",
    "            dic[(i,j)] = ans\n",
    "            return ans\n",
    "        return dfs(0,m-1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        def f(t):\n",
    "            if t < 0: return -1\n",
    "            res = 0\n",
    "            for x, c in zip(nums, cost):\n",
    "                res += abs(x - t) * c\n",
    "            return res\n",
    "\n",
    "        l,r = -1, int(1e18)\n",
    "        while l + 1 < r:\n",
    "            m = l + r >> 1\n",
    "            if  f(m) > f(m-1):\n",
    "                 r = m\n",
    "            else:\n",
    "                 l = m\n",
    "        return f(l)\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        def check(k):\n",
    "            t = k + 1\n",
    "            s1 = s2 = 0\n",
    "            for i, num in enumerate(nums):\n",
    "                s1 += abs(k - num) * cost[i]\n",
    "                s2 += abs(t - num) * cost[i]\n",
    "            if s1 < s2:\n",
    "                return 1, s1\n",
    "            elif s1 == s2:\n",
    "                return 0, s1\n",
    "            else:\n",
    "                return 2, s2\n",
    "        l, r = min(nums), max(nums)\n",
    "        if l == r:\n",
    "            return 0\n",
    "        ans = 0\n",
    "        while l < r:\n",
    "            mid = (l + r) // 2\n",
    "            state, ans = check(mid)\n",
    "            if state == 0:\n",
    "                return ans\n",
    "            elif state == 1:\n",
    "                r = mid\n",
    "            else:\n",
    "                l = mid + 1\n",
    "        return ans\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        n = len(nums)\n",
    "        left, right = min(nums), max(cost)\n",
    "        @cache\n",
    "        def fun(e):\n",
    "            res = 0\n",
    "            for i in range(n):\n",
    "                res += abs(e - nums[i]) * cost[i]\n",
    "            return res\n",
    "        while left <= right:\n",
    "            mid = (left + right) // 2\n",
    "            if fun(mid+1) > fun(mid) < fun(mid-1):\n",
    "                return fun(mid)\n",
    "            elif fun(mid-1) > fun(mid+1):\n",
    "                left = mid+1\n",
    "            else:\n",
    "                right = mid-1\n",
    "        return min(fun(left), fun(right))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from typing import List\n",
    "\n",
    "INF = int(4e18)\n",
    "\n",
    "\n",
    "def minimize(fun: Callable[[int], int], lower: int, upper: int) -> int:\n",
    "    \"\"\"三分法求`严格凸函数fun`在`[lower,upper]`间的最小值\"\"\"\n",
    "    res = INF\n",
    "    while (upper - lower) >= 3:\n",
    "        diff = (upper - lower) // 3\n",
    "        mid1 = lower + diff\n",
    "        mid2 = upper - diff\n",
    "        if fun(mid1) > fun(mid2):\n",
    "            lower = mid1\n",
    "        else:\n",
    "            upper = mid2\n",
    "\n",
    "    while lower <= upper:\n",
    "        cand = fun(lower)\n",
    "        res = cand if cand < res else res\n",
    "        lower += 1\n",
    "\n",
    "    return res\n",
    "\n",
    "\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        \"\"\"三分法求严格凸函数最值\"\"\"\n",
    "\n",
    "        def fun(pos: int) -> int:\n",
    "            return sum(abs((num - pos)) * c for num, c in zip(nums, cost))\n",
    "\n",
    "        return minimize(fun, min(nums), max(nums))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from typing import List\n",
    "from typing import Callable, Tuple\n",
    "\n",
    "\n",
    "INF = int(1e18)\n",
    "\n",
    "\n",
    "def minimize(fun: Callable[[int], int], left: int, right: int) -> Tuple[int, int]:\n",
    "    \"\"\"斐波那契搜索求`凸函数fun`在`[left,right]`间的极小值.\"\"\"\n",
    "    return fibonacciSearch(fun, left, right, min=True)\n",
    "\n",
    "\n",
    "def maximize(fun: Callable[[int], int], left: int, right: int) -> Tuple[int, int]:\n",
    "    \"\"\"斐波那契搜索求`凸函数fun`在`[left,right]`间的极大值.\"\"\"\n",
    "    return fibonacciSearch(fun, left, right, min=False)\n",
    "\n",
    "\n",
    "def fibonacciSearch(f: Callable[[int], int], left: int, right: int, min: bool) -> Tuple[int, int]:\n",
    "    \"\"\"斐波那契搜索寻找[left,right]中的一个极值点,不要求单峰性质.\n",
    "    Args:\n",
    "        f: 目标函数.\n",
    "        left: 搜索区间左端点(包含).\n",
    "        right: 搜索区间右端点(包含).\n",
    "        min: 是否寻找最小值.\n",
    "    Returns:\n",
    "        极值点的横坐标x和纵坐标f(x).\n",
    "    \"\"\"\n",
    "    assert left <= right\n",
    "    a, b, c, d = left, left + 1, left + 2, left + 3\n",
    "    n = 0\n",
    "    while d < right:\n",
    "        b = c\n",
    "        c = d\n",
    "        d = b + c - a\n",
    "        n += 1\n",
    "\n",
    "    def get(i: int) -> int:\n",
    "        if right < i:\n",
    "            return INF\n",
    "        return f(i) if min else -f(i)\n",
    "\n",
    "    ya, yb, yc, yd = get(a), get(b), get(c), get(d)\n",
    "    for _ in range(n):\n",
    "        if yb < yc:\n",
    "            d = c\n",
    "            c = b\n",
    "            b = a + d - c\n",
    "            yd = yc\n",
    "            yc = yb\n",
    "            yb = get(b)\n",
    "        else:\n",
    "            a = b\n",
    "            b = c\n",
    "            c = a + d - b\n",
    "            ya = yb\n",
    "            yb = yc\n",
    "            yc = get(c)\n",
    "\n",
    "    x = a\n",
    "    y = ya\n",
    "    if yb < y:\n",
    "        x = b\n",
    "        y = yb\n",
    "    if yc < y:\n",
    "        x = c\n",
    "        y = yc\n",
    "    if yd < y:\n",
    "        x = d\n",
    "        y = yd\n",
    "\n",
    "    return (x, y) if min else (x, -y)\n",
    "\n",
    "\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        \"\"\"三分法求严格凸函数最值\"\"\"\n",
    "\n",
    "        def fun(pos: int) -> int:\n",
    "            return sum(abs((num - pos)) * c for num, c in zip(nums, cost))\n",
    "\n",
    "        return minimize(fun, min(nums), max(nums))[1]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from typing import List\n",
    "\n",
    "from typing import Callable, Tuple\n",
    "\n",
    "\n",
    "INF = int(1e18)\n",
    "\n",
    "\n",
    "def fibonacciSearch(f: Callable[[int], int], start: int, end: int, min: bool) -> Tuple[int, int]:\n",
    "    \"\"\"斐波那契搜索寻找[start,end)中的一个极值点,不要求单峰性质.\n",
    "    Args:\n",
    "        f: 目标函数.\n",
    "        start: 搜索区间左端点(包含).\n",
    "        end: 搜索区间右端点(不包含).\n",
    "        min: 是否寻找最小值.\n",
    "    Returns:\n",
    "        极值点的横坐标x和纵坐标f(x).\n",
    "    \"\"\"\n",
    "    assert start <= end\n",
    "    end -= 1\n",
    "    a, b, c, d = start, start + 1, start + 2, start + 3\n",
    "    n = 0\n",
    "    while d < end:\n",
    "        b = c\n",
    "        c = d\n",
    "        d = b + c - a\n",
    "        n += 1\n",
    "\n",
    "    def get(i: int) -> int:\n",
    "        if end < i:\n",
    "            return INF\n",
    "        return f(i) if min else -f(i)\n",
    "\n",
    "    ya, yb, yc, yd = get(a), get(b), get(c), get(d)\n",
    "    for _ in range(n):\n",
    "        if yb < yc:\n",
    "            d = c\n",
    "            c = b\n",
    "            b = a + d - c\n",
    "            yd = yc\n",
    "            yc = yb\n",
    "            yb = get(b)\n",
    "        else:\n",
    "            a = b\n",
    "            b = c\n",
    "            c = a + d - b\n",
    "            ya = yb\n",
    "            yb = yc\n",
    "            yc = get(c)\n",
    "\n",
    "    x = a\n",
    "    y = ya\n",
    "    if yb < y:\n",
    "        x = b\n",
    "        y = yb\n",
    "    if yc < y:\n",
    "        x = c\n",
    "        y = yc\n",
    "    if yd < y:\n",
    "        x = d\n",
    "        y = yd\n",
    "\n",
    "    return (x, y) if min else (x, -y)\n",
    "\n",
    "\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        \"\"\"三分法求严格凸函数最值\"\"\"\n",
    "\n",
    "        def fun(pos: int) -> int:\n",
    "            return sum(abs((num - pos)) * c for num, c in zip(nums, cost))\n",
    "\n",
    "        return fibonacciSearch(fun, min(nums), max(nums)+1, min=True)[1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        n = len(nums)\n",
    "        minn = min(nums)\n",
    "        maxx = max(nums)\n",
    "        left, right = minn, maxx\n",
    "        while left < right:\n",
    "            # print(left, right)\n",
    "            mid_left = (left+right)//2\n",
    "            mid_right = (left+right)//2+1\n",
    "            tmp_left = tmp_right = 0\n",
    "            for i in range(n):\n",
    "                tmp_left += cost[i]*abs(mid_left-nums[i])\n",
    "                tmp_right += cost[i]*abs(mid_right-nums[i])\n",
    "            if tmp_left < tmp_right:\n",
    "                right = mid_left\n",
    "            else:\n",
    "                left = mid_right\n",
    "        return sum([cost[i]*abs(left-nums[i]) for i in range(n)])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        n = len(nums)\n",
    "        ind = list(range(n))\n",
    "        ind.sort(key=lambda it: nums[it])\n",
    "        s = sum(cost)\n",
    "        pre = 0\n",
    "        for i in ind:\n",
    "            pre += cost[i]\n",
    "            if pre >= s/2:\n",
    "                x = nums[i]\n",
    "                return sum(abs(nums[j]-x)*cost[j] for j in range(n))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums, cost):\n",
    "        res = 0\n",
    "        sum_cost = sum(cost)\n",
    "        num = sum_cost // 2\n",
    "        val = -1\n",
    "        cnt = 0\n",
    "        n = len(nums)\n",
    "        pos = list(range(n))\n",
    "\n",
    "        pos.sort(key=lambda i: nums[i])\n",
    "\n",
    "        for i in range(n):\n",
    "            cnt += cost[pos[i]]\n",
    "            if cnt > num:\n",
    "                val = nums[pos[i]]\n",
    "                break\n",
    "\n",
    "        for i in range(n):\n",
    "            res += cost[i] * abs(nums[i] - val)\n",
    "\n",
    "        return res\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        def get_slope(n):\n",
    "            r = 0\n",
    "            for num, c in zip(nums, cost):\n",
    "                if num < n:\n",
    "                    r += c\n",
    "                elif num > n:\n",
    "                    r -= c\n",
    "            return r\n",
    "        min_ = min(nums)\n",
    "        max_ = max(nums) + 1\n",
    "        n = len(nums)\n",
    "        a = bisect.bisect_left(range(min_, max_), 0, key=get_slope)  # 找到斜率大于等于0的第一个值\n",
    "        num_n = min_ + a - 1\n",
    "        num_p = min_ + a\n",
    "        r_1 = sum([cost[i] * abs(nums[i] - num_n) for i in range(n)])\n",
    "        r_2 = sum([cost[i] * abs(nums[i] - num_p) for i in range(n)])\n",
    "        return min(r_1, r_2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        n = len(nums)\n",
    "        indices = sorted(range(n), key=lambda i: nums[i])\n",
    "        cur_sum = -sum(cost)\n",
    "        opt = None\n",
    "        for i in indices:\n",
    "            cur_sum += cost[i] * 2\n",
    "            if cur_sum >= 0:\n",
    "                opt = i\n",
    "                break\n",
    "        return sum(abs(nums[i] - nums[opt]) * cost[i] for i in range(n))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        n = len(nums)\n",
    "        idx = sorted(range(n), key = lambda x: nums[x])\n",
    "        if nums[idx[0]] == nums[idx[-1]]:   return 0\n",
    "\n",
    "        ans = float(inf)\n",
    "        sumCost = sum(cost)\n",
    "        totalCost = sum(nums[i] * cost[i] for i in range(n))\n",
    "        for i in range(n):\n",
    "            ans = min(ans, abs(totalCost - sumCost * nums[idx[i]]))\n",
    "            totalCost -= 2 * nums[idx[i]] * cost[idx[i]]\n",
    "            sumCost -= 2 * cost[idx[i]]\n",
    "        return ans"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        n = len(nums)\n",
    "        idx = sorted(range(n), key = lambda x: nums[x])\n",
    "        if nums[idx[0]] == nums[idx[-1]]:   return 0\n",
    "\n",
    "        ans = float(inf)\n",
    "        sumCost = sum(cost)\n",
    "        totalCost = sum(nums[i] * cost[i] for i in range(n))\n",
    "        for i in range(n):\n",
    "            ans = min(ans, abs(totalCost - sumCost * nums[idx[i]]))\n",
    "            totalCost -= 2 * nums[idx[i]] * cost[idx[i]]\n",
    "            sumCost -= 2 * cost[idx[i]]\n",
    "        return ans"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        \n",
    "        n = len(nums)\n",
    "        index = [i for i in range(n)]\n",
    "        index.sort(key=lambda i : nums[i]) \n",
    "        \n",
    "        S = (sum(cost) + 1) // 2\n",
    "        a = 0\n",
    "        b = -1 \n",
    "        for i in index:\n",
    "            if a + cost[i] >= S:\n",
    "                b = nums[i] \n",
    "                break \n",
    "            a+= cost[i] \n",
    "        ans = 0 \n",
    "        for i in range(n):\n",
    "            ans += abs(nums[i] - b) * cost[i] \n",
    "        return ans \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        n = len(nums)\n",
    "        idx = sorted(range(n), key = lambda x: nums[x])\n",
    "        if nums[idx[0]] == nums[idx[-1]]:   return 0\n",
    "\n",
    "        ans = float(inf)\n",
    "        sumCost = sum(cost)\n",
    "        totalCost = sum(nums[i] * cost[i] for i in range(n))\n",
    "        for i in range(n):\n",
    "            ans = min(ans, abs(totalCost - sumCost * nums[idx[i]]))\n",
    "            totalCost -= 2 * nums[idx[i]] * cost[idx[i]]\n",
    "            sumCost -= 2 * cost[idx[i]]\n",
    "        return ans"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "# 枚举 + 考察变化量\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        a = sorted(zip(nums, cost))\n",
    "        ans = total = sum((x - a[0][0]) * c for x, c in a)\n",
    "        sum_cost = sum(cost)\n",
    "        for (x0, c), (x1, _) in pairwise(a):\n",
    "            sum_cost -= c * 2\n",
    "            total -= sum_cost * (x1 - x0)\n",
    "            ans = min(ans, total)\n",
    "        return ans"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        origin = sorted(zip(nums, cost))\n",
    "        test, middle = 0, (sum(cost) + 1) // 2\n",
    "        for i, j in origin:\n",
    "            test += j\n",
    "            if test >= middle:\n",
    "                return sum(abs(z - i) * j for z, j in origin)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        n = len(nums)\n",
    "        mid = sum(cost) // 2 \n",
    "        cur = 0\n",
    "        for num, c in sorted(zip(nums, cost)):\n",
    "            cur += c \n",
    "            if cur > mid:\n",
    "                break \n",
    "        x = num \n",
    "        return sum(abs(num - x) * c for num, c in zip(nums, cost))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        a = sorted(zip(nums, cost))\n",
    "        s, mid = 0, (sum(cost) + 1) // 2\n",
    "        for x, c in a:\n",
    "            s += c\n",
    "            if s >= mid:\n",
    "                return sum(abs(y - x) * c for y, c in a)  # 把所有数变成 x\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        mid = sum(cost)// 2 \n",
    "        s = 0\n",
    "        for num, c in sorted(zip(nums, cost)):\n",
    "            s += c \n",
    "            if s > mid:\n",
    "                break \n",
    "        return sum(abs(x - num) * c for x, c in zip(nums, cost))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "\n",
    "        a = sorted(zip(nums, cost))\n",
    "\n",
    "        s, mid = 0, (sum(cost) + 1) // 2\n",
    "\n",
    "        for x, c in a:\n",
    "\n",
    "            s += c\n",
    "\n",
    "            if s >= mid:\n",
    "\n",
    "                return sum(abs(y - x) * c for y, c in a)  # 把所有数变成 x\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "# 中位数贪心\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        a = sorted(zip(nums, cost))\n",
    "        s, mid = 0, (sum(cost) + 1) // 2\n",
    "        for x, c in a:\n",
    "            s += c\n",
    "            if s >= mid:\n",
    "                return sum(abs(y - x) * c for y, c in a)  # 把所有数变成 x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        if not nums: return 0\n",
    "\n",
    "        n = len(nums)\n",
    "\n",
    "        # the target number must be in (min(nums), max(nums))\n",
    "        # given the target number x, the cost is easy to compute\n",
    "        # sum_{0<=i<n} abs(nums[i] - x) * cost[i]\n",
    "        # sum_{0<=i<n} sum_{0<=j<cost[i]} abs(nums[i] - x)\n",
    "        # expand the nums wrt cost\n",
    "        # find the median\n",
    "        arr = sorted(zip(nums, cost))\n",
    "\n",
    "        # find median at total // 2\n",
    "        median = nums[0]\n",
    "        median_idx, cnt = sum(cost) // 2, 0\n",
    "        for val, freq in arr:\n",
    "            cnt += freq\n",
    "            # current index is cnt - 1 >= median_idx\n",
    "            if cnt > median_idx:\n",
    "                median = val\n",
    "                break\n",
    "        \n",
    "        return sum(abs(val - median) * freq for val, freq in arr)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "\n",
    "        a = sorted(zip(nums, cost))\n",
    "\n",
    "        ans = total = sum((x - a[0][0]) * c for x, c in a)\n",
    "\n",
    "        sum_cost = sum(cost)\n",
    "\n",
    "        for (x0, c), (x1, _) in pairwise(a):\n",
    "\n",
    "            sum_cost -= c * 2\n",
    "\n",
    "            total -= sum_cost * (x1 - x0)\n",
    "\n",
    "            ans = min(ans, total)\n",
    "\n",
    "        return ans\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        a = sorted(list(zip(nums, cost)))\n",
    "        mid = (sum(cost) + 1) // 2    # 参考大样本统计找中位数，可能是奇数，要上取整\n",
    "        s = 0\n",
    "        for x, c in a:\n",
    "            s += c  # 找到中位数\n",
    "            # 中位数贪心\n",
    "            if s >= mid:\n",
    "                return sum(abs(x - y) * c for y, c in a)\n",
    "\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        dst = []\n",
    "        tot = sum(cost)\n",
    "        for x, c in zip(nums, cost):\n",
    "            dst.append((x, c))\n",
    "        dst.sort()\n",
    "        n = len(dst)\n",
    "        cnt = res = 0\n",
    "        for i in range(n):\n",
    "            if cnt + dst[i][1] > tot // 2 :\n",
    "                res = dst[i][0]\n",
    "                break\n",
    "            cnt += dst[i][1]\n",
    "        #print(dst, res)\n",
    "        return sum(abs(res - x) * c for x, c in dst)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        # a=sorted(zip(nums,cost))\n",
    "        # ans=total=sum((x-a[0][0])*c for x,c in a)\n",
    "        # sum_cost=sum(cost)\n",
    "        # for (x0,c),(x1,_) in pairwise(a):\n",
    "        #     sum_cost-=c*2\n",
    "        #     total-=sum_cost*(x1-x0)\n",
    "        #     ans=min(ans,total)\n",
    "        # return ans\n",
    "        a=sorted(zip(nums,cost))\n",
    "        s,mid=0,(sum(cost)+1)//2#出现次数向上取整 中位数\n",
    "        for x,c in a:\n",
    "            s+=c\n",
    "            if s>=mid:\n",
    "                return sum(abs(y-x)*c for y,c in a)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        temp = sorted(zip(nums, cost))\n",
    "        res = 0\n",
    "        preSumCost = 0\n",
    "        postSumCost = sum(cost)\n",
    "        for num, c in temp:\n",
    "            res += (num - temp[0][0]) * c\n",
    "        currTotalCost = res\n",
    "        for i in range(1, len(nums)):\n",
    "            preSumCost += temp[i - 1][1]\n",
    "            postSumCost -= temp[i - 1][1]\n",
    "            currTotalCost += (preSumCost - postSumCost) * (temp[i][0] - temp[i - 1][0])\n",
    "            res = min(res, currTotalCost)\n",
    "        return res"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "\n",
    "# 本题可以先对元素下标按照nums数组（或对{nums[i], cost[i]}的对）排序，便于分析。另一个可以将cost看成是数字出现的频次，也便于分析和理解，以下直接将cost视为元素出现的频次。\n",
    "# 有以下结论：合并到的相同数肯定是nums中的数，因为假设对（排序后的）数组操作后现在跟某个下标i~i+1位置的数x相同，用cntLessX / cntGreaterX分别表示原数组中比x小 / 大的数的出现频次，那么如果cntlessX >= cntGreaterX，那么修改目标数x为x-1时，将会减少cntLessX次操作（每个比x小的数操作次数都减少一次），而增加cntGreaterX次操作（同理比x大的每个数的操作次数都会增加一次），由于cntLessX > cntGreaterX，所以总的操作次数变化：- cntLessX + cntGreaterX是减少的，这种情况可以一直保持到目标数修改为nums{i}，如果cntGreaterX + cost[i] >= cntLessX - cost[i]，那么表示继续减小目标值不会导致总操作次数减少，所以也即nums[i]就为答案最少操作次数的目标值，如果一开始的cntLessX == cntGreaterX也没关系，将x减少到nums[i]不会导致操作次数变化，但是证明了目标值肯定可以为某个nums[i]。\n",
    "# 根据上面的结论及证明过程，可以得到第一种解法，先求出转移到数组中最大的数的代价，并逐步向较小的数转移，维护目标值在区间nums[i + 1] ~ nums[i]内变化（每次目标值减少1）时，操作次数的减少与增加量，也即小于等于nums[i]的数cntLess有几个，大于等于nums[i + 1]的数cntGreater有几个，如果cntLess > cntGreater，那么可以继续减小目标值，则一次性计算目标值从nums[i + 1]减小到nums[i]的操作数变化：operCnt += (nums[i + 1] - nums[i]) * (-cntLess + cntGreater)，并根据nums[i]的值更新cntLess -= nums[i]，cntGreater += nums[i]。继续检查下一个区间nums[i] ~ nums[i-1]的变化情况。\n",
    "# 根据第一种解法可以发现，题目相当于需要找到一个最大的i，满足条件sum(cost[0..i]) >= sum(cost[i + 1..])，则答案中的相同的数应该为nums[i]，再依次计算比nums[i]小的数修改成nums[i]的代价及比nums[i]大的数修改成nums[i]的代价即可，而找下标i可以通过枚举并累加cost[i]，求出某个下标i时sum(cost[0..i]) > tot - sum(cost[0..i])即找到了下标i，其中tot为cost的总和。\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        ps = sorted(zip(nums, cost))\n",
    "        totFreq = sum(cost)\n",
    "        preFreq = 0\n",
    "        for i, (x, c) in enumerate(ps):\n",
    "            preFreq += c\n",
    "            if preFreq >= totFreq - preFreq:\n",
    "                sameNum = x\n",
    "                ans = sum((sameNum - x) * c for x,\n",
    "                          c in ps[:i]) + sum((x - sameNum) * c for x, c in ps[i + 1:])\n",
    "                return ans\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        a = sorted(zip(nums, cost))\n",
    "        ans = total = sum((x - a[0][0]) * c for x, c in a)\n",
    "        sum_cost = sum(cost)\n",
    "        for (x0, c), (x1, _) in pairwise(a):\n",
    "            sum_cost -= c * 2\n",
    "            total -= sum_cost * (x1 - x0)\n",
    "            ans = min(ans, total)\n",
    "        return ans\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from typing import List\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        combined = sorted(zip(nums, cost))\n",
    "        total_cost = 0\n",
    "        left_sum = 0\n",
    "        right_sum = sum(cost)\n",
    "\n",
    "        # 开始时，x为最小的nums值，所有其他nums都需要增加到这个值\n",
    "        for num, c in combined:\n",
    "            total_cost += (num - combined[0][0]) * c\n",
    "\n",
    "        min_cost = total_cost\n",
    "        for i in range(1, len(nums)):\n",
    "            # 当x从nums[i-1]增加到nums[i]时，左侧的数字都需要增加，右侧的数字都需要减少\n",
    "            left_sum += combined[i-1][1]\n",
    "            right_sum -= combined[i-1][1]\n",
    "            total_cost += (combined[i][0] - combined[i-1][0]) * left_sum\n",
    "            total_cost -= (combined[i][0] - combined[i-1][0]) * right_sum\n",
    "            min_cost = min(min_cost, total_cost)\n",
    "\n",
    "        return min_cost\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        a = sorted(zip(nums, cost))\n",
    "        tota = 0\n",
    "        for i,j in a:\n",
    "            tota += (i-a[0][0])*j\n",
    "        sum_cost_jian = sum(cost)\n",
    "        sum_cost_zeng = 0\n",
    "        ans = tota\n",
    "        for i in range(len(a)-1):\n",
    "            sum_cost_jian -= a[i][1]\n",
    "            sum_cost_zeng += a[i][1]\n",
    "            tota += (a[i+1][0] - a[i][0])*sum_cost_zeng # 增加的\n",
    "            tota -= (a[i+1][0] - a[i][0])*sum_cost_jian # 减少的 \n",
    "            ans = min(ans, tota)\n",
    "        return ans"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        a = sorted(zip(nums, cost))\n",
    "        ans = total = sum((x - a[0][0]) * c for x, c in a)\n",
    "        sum_cost = sum(cost)\n",
    "        for (x0, c), (x1, _) in pairwise(a):\n",
    "            sum_cost -= c * 2\n",
    "            total -= sum_cost * (x1 - x0)\n",
    "            ans = min(ans, total)\n",
    "        return ans\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        a = sorted(zip(nums, cost))\n",
    "        ans = total = sum((x - a[0][0]) * c for x, c in a)\n",
    "        sum_cost = sum(cost)\n",
    "        for (x0, c), (x1, _) in pairwise(a):\n",
    "            sum_cost -= c * 2\n",
    "            total -= sum_cost * (x1 - x0)\n",
    "            ans = min(ans, total)\n",
    "        return ans\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        # https://leetcode.cn/problems/minimum-cost-to-make-array-equal/submissions/475390779/\n",
    "        a = sorted(zip(nums, cost))\n",
    "        s, mid = 0, (sum(cost) + 1) // 2\n",
    "        for x, c in a:\n",
    "            s += c\n",
    "            # 找到了中位数\n",
    "            if s >= mid:\n",
    "                return sum(abs(y - x) * c for y, c in a)\n",
    "\n",
    "\n",
    "        \n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        a = sorted(zip(nums, cost))\n",
    "        ans = total = sum((x - a[0][0]) * c for x, c in a)\n",
    "        sum_cost = sum(cost)\n",
    "        for (x0, c), (x1, _) in pairwise(a):\n",
    "            sum_cost -= c * 2\n",
    "            total -= sum_cost * (x1 - x0)\n",
    "            ans = min(ans, total)\n",
    "        return ans\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    #方法一 中位数贪心，灵茶山艾府\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        a = sorted(zip(nums, cost))\n",
    "        s, mid = 0, (sum(cost) + 1) // 2\n",
    "        for x, c in a:\n",
    "            s += c\n",
    "            if s >= mid:\n",
    "                return sum(abs(y - x) * c for y, c in a)# 把所有数变成 x\n",
    "\n",
    "\n",
    "'''\n",
    "方法2，枚举+考察变化量\n",
    "a = sorted(zip(nums, cost))\n",
    "ans = total = sum((x - a[0][0]) * c for x, c in a)\n",
    "sum_cost = sum(cost)\n",
    "for (x0, c), (x1,_) in pairwise(a):\n",
    "    sum_cost -= c * 2\n",
    "    total -= sum_cost * (x1 - x0)\n",
    "    ans = min(ans, total)\n",
    "return ans\n",
    "'''"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        a = sorted(zip(nums, cost))\n",
    "        s, mid = 0, (sum(cost) + 1) // 2\n",
    "        for x, c in a:\n",
    "            s += c\n",
    "            if s >= mid:\n",
    "                return sum(abs(y - x) * c for y, c in a)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        all_number = sorted(zip(nums, cost))\n",
    "        mid = (sum(cost) + 1) // 2\n",
    "        s = 0\n",
    "        for i, x in all_number:\n",
    "            s += x\n",
    "            if s >= mid:\n",
    "                return sum(abs(y - i) * x for y, x in all_number)\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        temp = sorted(zip(nums, cost))\n",
    "        res = 0\n",
    "        preSumCost = 0\n",
    "        postSumCost = sum(cost)\n",
    "        for num, c in temp:\n",
    "            res += (num - temp[0][0]) * c\n",
    "        currTotalCost = res\n",
    "        print(preSumCost, postSumCost, currTotalCost)\n",
    "        for i in range(1, len(nums)):\n",
    "            preSumCost += temp[i - 1][1]\n",
    "            postSumCost -= temp[i - 1][1]\n",
    "            currTotalCost += (preSumCost - postSumCost) * (temp[i][0] - temp[i - 1][0])\n",
    "            print(preSumCost, postSumCost, currTotalCost)\n",
    "            res = min(res, currTotalCost)\n",
    "        return res"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        # 模拟\n",
    "        a = sorted(zip(nums, cost))\n",
    "        # 现在target = nums[0]\n",
    "        ans = total = sum((x - a[0][0]) * c for x, c in a)\n",
    "        sum_cost = sum(cost)\n",
    "        for (x0, c), (x1, _) in pairwise(a):\n",
    "            # 现在target = x1\n",
    "            # 分析变化量\n",
    "            sum_cost -= c * 2\n",
    "            total -= sum_cost * (x1 - x0)\n",
    "            ans = min(ans, total)\n",
    "        return ans\n",
    "\n",
    "\n",
    "        \n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        # https://leetcode.cn/problems/minimum-cost-to-make-array-equal/submissions/475390779/\n",
    "        # 模拟\n",
    "        a = sorted(zip(nums, cost))\n",
    "        # 现在target = nums[0]\n",
    "        ans = total = sum((x - a[0][0]) * c for x, c in a)\n",
    "        sum_cost = sum(cost)\n",
    "        for (x0, c), (x1, _) in pairwise(a):\n",
    "            # 现在target = x1\n",
    "            # 分析变化量\n",
    "            sum_cost -= c * 2\n",
    "            total -= sum_cost * (x1 - x0)\n",
    "            ans = min(ans, total)\n",
    "        return ans\n",
    "\n",
    "\n",
    "        \n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        n = zip(nums, cost) \n",
    "        n = sorted(n, key = lambda x: x[0])\n",
    "        t, l, s = 0, len(nums), sum(cost)\n",
    "        for i in range(l):\n",
    "            t += n[i][1]\n",
    "            s -= n[i][1]\n",
    "            if t < s:\n",
    "                continue\n",
    "            else:\n",
    "                return sum((abs(n[j][0] - n[i][0]) * n[j][1]) for j in range(l)) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        n = zip(nums, cost) \n",
    "        n = sorted(n, key = lambda x: x[0])\n",
    "        #print(n)\n",
    "        t, l, s = 0, len(nums), sum(cost)\n",
    "        for i in range(l):\n",
    "            t += n[i][1]\n",
    "            s -= n[i][1]\n",
    "            #print(n[i][])\n",
    "            if t < s:\n",
    "                continue\n",
    "            else:\n",
    "                #print(i, n)\n",
    "                #for j in range(l):\n",
    "                    #print((abs(n[j][0] - n[i][0]) * n[j][1]), n[j][0], n[i][0])\n",
    "                return sum((abs(n[j][0] - n[i][0]) * n[j][1]) for j in range(l)) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        n = zip(nums, cost)\n",
    "        n = sorted(n, key = lambda x : x[0])\n",
    "        #print(n)\n",
    "        l = len(nums)\n",
    "        s_nums = -sum(n[i][1] for i in range(l))\n",
    "        for i in range(l):\n",
    "            s_nums += 2 * n[i][1]\n",
    "            if s_nums >= 0:\n",
    "                target = n[i][0]\n",
    "                break\n",
    "        ans = sum(abs(n[i][0] - target) * n[i][1] for i in range(l))\n",
    "        return ans\n",
    "\n",
    "\n",
    "\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        nums=sorted([(nums[i],cost[i]) for i in range(len(nums))])\n",
    "        totalcost,totalsum,idx,sumnums=0,0,0,0\n",
    "        for i in nums:\n",
    "            totalcost+=(i[0]-nums[0][0])*i[1]\n",
    "            sumnums+=i[1]\n",
    "        while(idx+1<len(nums)):\n",
    "            totalsum+=nums[idx][1]\n",
    "            change=(sumnums-2*totalsum)*(nums[idx+1][0]-nums[idx][0])\n",
    "            if(change>=0):totalcost-=change;idx+=1\n",
    "            else:break\n",
    "        return totalcost"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: list[int], cost: list[int]) -> int:\n",
    "        totnums=sum(cost)\n",
    "        ans = 2**53\n",
    "        def totcost(n):\n",
    "            t=0\n",
    "            for i in range(len(nums)):\n",
    "                t +=abs(n-nums[i])*cost[i]\n",
    "                if t>=ans:\n",
    "                    return t\n",
    "            return t\n",
    "        z = list(zip(nums,cost))\n",
    "        z.sort(key = lambda x :x[0])\n",
    "        if totnums%2==1:\n",
    "            target = totnums//2+1\n",
    "            for num in z:\n",
    "                if  target>num[1]:\n",
    "                    target-=num[1]\n",
    "                else:\n",
    "                    ans = totcost(num[0])\n",
    "                    break\n",
    "        if totnums%2==0:\n",
    "            target = totnums//2\n",
    "            for i in range(len(z)):\n",
    "                num = z[i]\n",
    "                if target>num[1]:\n",
    "                    target-=num[1]\n",
    "                else:\n",
    "                    if target<num[1]:   \n",
    "                        ans = totcost(num[0])\n",
    "                    else:\n",
    "                        ans = totcost((z[i][0]+z[i+1][0])//2)\n",
    "                    break\n",
    "        return ans "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        n = len(nums)\n",
    "        s = sum(cost)\n",
    "        c = 0\n",
    "        l = []\n",
    "        ans = 0\n",
    "        for nn,cc in zip(nums,cost):\n",
    "            l.append([nn,cc])\n",
    "        l.sort()\n",
    "        for nn,cc in l:\n",
    "            c+=cc\n",
    "            if c>=s/2:\n",
    "                av=nn\n",
    "                break\n",
    "        for nn,cc in l:\n",
    "            ans += cc*abs(nn-av)\n",
    "        return ans"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        arr=[]\n",
    "        for l,r in zip(nums,cost):\n",
    "            arr.append([l,r])\n",
    "        arr.sort()\n",
    "        n=len(nums)\n",
    "        tot=0\n",
    "        for i in range(1,n):\n",
    "            tot+=(arr[i][0]-arr[0][0])*arr[i][1]\n",
    "        ans=tot\n",
    "        sum_cost=sum(cost)\n",
    "        for i in range(1,n):\n",
    "            sum_cost-=2*arr[i-1][1]\n",
    "            tot-=sum_cost*(arr[i][0]-arr[i-1][0])\n",
    "            ans=min(ans,tot)\n",
    "        return ans"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        arr=[]\n",
    "        for l,r in zip(nums,cost):\n",
    "            arr.append([l,r])\n",
    "        arr.sort()\n",
    "        n=len(nums)\n",
    "        tot=0\n",
    "        for i in range(1,n):\n",
    "            tot+=(arr[i][0]-arr[0][0])*arr[i][1]\n",
    "        ans=tot\n",
    "        sum_cost=sum(cost)\n",
    "        pre_cost=0\n",
    "        for i in range(1,n):\n",
    "            sum_cost-=arr[i-1][1]\n",
    "            pre_cost+=arr[i-1][1]\n",
    "            tot-=(sum_cost)*(arr[i][0]-arr[i-1][0])\n",
    "            tot+=(pre_cost)*(arr[i][0]-arr[i-1][0])\n",
    "            ans=min(ans,tot)\n",
    "        return ans"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        n=len(nums)\n",
    "        ls=[]\n",
    "        for i in range(n):\n",
    "            ls.append([nums[i],cost[i]])\n",
    "        ls.sort()\n",
    "        s=(sum(cost)+1)//2\n",
    "        i=0\n",
    "        now=0\n",
    "        #print(ls)\n",
    "        while now<s:\n",
    "            now+=ls[i][1]\n",
    "            i+=1\n",
    "        mid=ls[i-1][0]\n",
    "        ans=0\n",
    "        #print(mid)\n",
    "        for i in range(n):\n",
    "            ans+=abs(mid-ls[i][0])*ls[i][1]\n",
    "        return ans"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        n = len(nums)\n",
    "        idx = list(range(n))\n",
    "        idx.sort(key=lambda i:nums[i])\n",
    "        s = [0] * (n + 1)\n",
    "        for i in range(n):\n",
    "            s[i + 1] = s[i] + cost[idx[i]]\n",
    "        ret = 0\n",
    "        x = nums[idx[0]]\n",
    "        for i in range(1, n):\n",
    "            ret += (nums[idx[i]] - x) * cost[idx[i]]\n",
    "        cnt = ret\n",
    "        for i in range(1, n):\n",
    "            cnt += (2 * s[i] - s[n]) * (nums[idx[i]] - nums[idx[i - 1]])\n",
    "            ret = min(ret, cnt)\n",
    "        return ret\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        n = len(nums)\n",
    "        idx = sorted(range(n), key=lambda i: nums[i])\n",
    "        accu = list(islice(accumulate(idx, func=lambda a, i: a+cost[i], initial=0), 1, None))\n",
    "        off = bisect_left(accu, accu[-1]//2)\n",
    "        if accu[off] * 2 < accu[-1]:\n",
    "            off += 1\n",
    "        v = nums[idx[off]]\n",
    "        return sum(abs(n-v)*c for n, c in zip(nums, cost))\n",
    "\n",
    "       "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "\n",
    "# 本题可以先对元素下标按照nums数组（或对{nums[i], cost[i]}的对）排序，便于分析。另一个可以将cost看成是数字出现的频次，也便于分析和理解，以下直接将cost视为元素出现的频次。\n",
    "# 有以下结论：合并到的相同数肯定是nums中的数，因为假设对（排序后的）数组操作后现在跟某个下标i~i+1位置的数x相同，用cntLessX / cntGreaterX分别表示原数组中比x小 / 大的数的出现频次，那么如果cntlessX >= cntGreaterX，那么修改目标数x为x-1时，将会减少cntLessX次操作（每个比x小的数操作次数都减少一次），而增加cntGreaterX次操作（同理比x大的每个数的操作次数都会增加一次），由于cntLessX > cntGreaterX，所以总的操作次数变化：- cntLessX + cntGreaterX是减少的，这种情况可以一直保持到目标数修改为nums{i}，如果cntGreaterX + cost[i] >= cntLessX - cost[i]，那么表示继续减小目标值不会导致总操作次数减少，所以也即nums[i]就为答案最少操作次数的目标值，如果一开始的cntLessX == cntGreaterX也没关系，将x减少到nums[i]不会导致操作次数变化，但是证明了目标值肯定可以为某个nums[i]。\n",
    "# 根据上面的结论及证明过程，可以得到第一种解法，先求出转移到数组中最大的数的代价，并逐步向较小的数转移，维护目标值在区间nums[i + 1] ~ nums[i]内变化（每次目标值减少1）时，操作次数的减少与增加量，也即小于等于nums[i]的数cntLess有几个，大于等于nums[i + 1]的数cntGreater有几个，如果cntLess > cntGreater，那么可以继续减小目标值，则一次性计算目标值从nums[i + 1]减小到nums[i]的操作数变化：operCnt += (nums[i + 1] - nums[i]) * (-cntLess + cntGreater)，并根据nums[i]的值更新cntLess -= nums[i]，cntGreater += nums[i]。继续检查下一个区间nums[i] ~ nums[i-1]的变化情况。\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        ps = sorted([[x, c] for x, c in zip(nums, cost)])\n",
    "        ans = lessCnt = greaterCnt = 0\n",
    "        maxNum = ps[-1][0]\n",
    "        for x, c in ps:\n",
    "            ans += (maxNum - x) * c\n",
    "            lessCnt += c\n",
    "        for i in range(len(ps)-1, -1, -1):\n",
    "            lessCnt -= ps[i][1]\n",
    "            greaterCnt += ps[i][1]\n",
    "            if lessCnt < greaterCnt:\n",
    "                break\n",
    "            ans += (-lessCnt + greaterCnt) * (ps[i][0] - ps[i-1][0])\n",
    "        return ans"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        a = sorted(zip(nums, cost))\n",
    "        mid = (sum(cost) + 1) // 2\n",
    "        s = 0\n",
    "        for x, c in a:\n",
    "            s += c\n",
    "            if s >= mid:\n",
    "                return sum([abs(t-x)*d for t, d in a])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        a = sorted(zip(nums, cost))\n",
    "        print(a)\n",
    "        s, mid = 0, (sum(cost) + 1) // 2\n",
    "        for x, c in a:\n",
    "            s += c\n",
    "            if s >= mid:\n",
    "                return sum(abs(y - x) * c for y, c in a)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        arr = [[x,y] for x, y in zip(nums, cost)]\n",
    "        arr.sort() \n",
    "        s, mid = 0, (sum(cost) + 1) // 2\n",
    "        for x,y in arr:\n",
    "            s += y \n",
    "            if s >= mid:\n",
    "                return sum([abs(a - x) * b for a, b in arr])\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "\n",
    "        cnt = Counter()\n",
    "        s = 0\n",
    "        for a, b in zip(nums, cost):\n",
    "            cnt[a] += b\n",
    "            s += a * b\n",
    "        totcnt = sum(cost)\n",
    "        arr = sorted(cnt.keys())\n",
    "        ans = inf\n",
    "        pres = cntp = 0\n",
    "        for num in arr:\n",
    "            cur = num * cntp - pres + s - pres - (totcnt - cntp) * num\n",
    "            pres += num * cnt[num]\n",
    "            cntp += cnt[num]\n",
    "            ans = min(ans, cur)\n",
    "        return ans\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "\n",
    "        cnt = Counter()\n",
    "        s = 0\n",
    "        for a, b in zip(nums, cost):\n",
    "            cnt[a] += b\n",
    "            s += a * b\n",
    "        totcnt = sum(cost)\n",
    "        arr = sorted(cnt.keys())\n",
    "        ans = inf\n",
    "        pres = cntp = 0\n",
    "        for num in arr:\n",
    "            cur = num * cntp - pres + s - pres - (totcnt - cntp) * num\n",
    "            pres += num * cnt[num]\n",
    "            cntp += cnt[num]\n",
    "            ans = min(ans, cur)\n",
    "        return ans\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        d = {}\n",
    "        for i, x in enumerate(nums):\n",
    "            if x in d:\n",
    "                d[x] += cost[i]\n",
    "            else:\n",
    "                d[x] = cost[i]\n",
    "        a = list(d.items())\n",
    "        a.sort()\n",
    "        n = len(a)\n",
    "        left, right, total = 0, 0, 0\n",
    "        for i in range(1, n):\n",
    "            right += a[i][1]\n",
    "            total += a[i][1] * (a[i][0] - a[0][0])\n",
    "        res = total\n",
    "        for i in range(1, n):\n",
    "            left += a[i-1][1]\n",
    "            total += (left - right) * (a[i][0] - a[i-1][0])\n",
    "            right -= a[i][1]\n",
    "            res = min(res, total)\n",
    "        return res"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        # sorting + prefix sum\n",
    "        n = len(nums)\n",
    "        nums_cost = list(zip(nums, cost))\n",
    "        nums_cost.sort(key = lambda x : (x[0], x[1]))\n",
    "        nums = list(map(lambda x : x[0], nums_cost))\n",
    "        cost = list(map(lambda x : x[1], nums_cost))\n",
    "\n",
    "        pfx_cost = [0] * n\n",
    "        pfx_cost[0] = cost[0]\n",
    "        for i in range(1, n):\n",
    "            pfx_cost[i] = pfx_cost[i - 1] + cost[i]\n",
    "        \n",
    "        res = sys.maxsize\n",
    "        curr_cost = 0\n",
    "        for i in range(1, n):\n",
    "            curr_cost += cost[i] * (nums[i] - nums[0])\n",
    "        res = min(res, curr_cost)\n",
    "        \n",
    "        for i in range(1, n):\n",
    "            curr_cost -= (nums[i] - nums[i - 1]) * (pfx_cost[-1] - pfx_cost[i - 1])\n",
    "            curr_cost += (nums[i] - nums[i - 1]) * (pfx_cost[i - 1])\n",
    "            res = min(res, curr_cost)\n",
    "        return res\n",
    "        \n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        \n",
    "        arr = []\n",
    "        for x,y in zip(nums, cost):\n",
    "            arr.append([x,y])\n",
    "        arr.sort(key=lambda x : x[0])\n",
    "        n = len(arr)\n",
    "        f = [0] * n \n",
    "        f[0] = arr[0][1]\n",
    "        for i in range(1, n):\n",
    "            f[i] = f[i-1] + arr[i][1]\n",
    "\n",
    "        def lower_bound(x):\n",
    "            l, r = 0, n\n",
    "            while l < r:\n",
    "                mid = (l + r) >> 1\n",
    "                if f[mid] >= x:\n",
    "                    r = mid \n",
    "                else:\n",
    "                    l = mid + 1 \n",
    "            return l \n",
    "        idx = lower_bound((f[n-1]+1)//2)\n",
    "        ans = 0 \n",
    "        for i in range(n):\n",
    "            ans += abs(arr[i][0] - arr[idx][0]) * arr[i][1]\n",
    "        return ans \n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        \n",
    "        arr = []\n",
    "        for x,y in zip(nums, cost):\n",
    "            arr.append([x,y])\n",
    "        arr.sort(key=lambda x : x[0])\n",
    "        n = len(arr)\n",
    "        f = [0] * n \n",
    "        f[0] = arr[0][1]\n",
    "        for i in range(1, n):\n",
    "            f[i] = f[i-1] + arr[i][1]\n",
    "\n",
    "        def lower_bound(x):\n",
    "            l, r = 0, n\n",
    "            while l < r:\n",
    "                mid = (l + r) >> 1\n",
    "                if f[mid] >= x:\n",
    "                    r = mid \n",
    "                else:\n",
    "                    l = mid + 1 \n",
    "            return l \n",
    "        idx = lower_bound(f[n-1]//2+1)\n",
    "        ans = 0 \n",
    "        for i in range(n):\n",
    "            ans += abs(arr[i][0] - arr[idx][0]) * arr[i][1]\n",
    "        return ans \n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\n",
    "        n = len(nums)\n",
    "        if n == 1:\n",
    "            return 0\n",
    "        nums = [(n, c) for n, c in zip(nums, cost)]\n",
    "        nums.sort()\n",
    "        pre_sum = [0] * n\n",
    "        suf_sum = [0] * n\n",
    "        for i in range(n - 1):\n",
    "            pre_sum[i + 1] = pre_sum[i] + nums[i][1]\n",
    "        for i in range(n - 1, 0, -1):\n",
    "            suf_sum[i - 1] = suf_sum[i] + nums[i][1]\n",
    "        pre = 0\n",
    "        suf = sum((nums[i][0] - nums[0][0]) * nums[i][1] for i in range(1, n))\n",
    "        ans = suf\n",
    "        for i in range(1, n):\n",
    "            diff = nums[i][0] - nums[i - 1][0]\n",
    "            pre += diff * pre_sum[i]\n",
    "            suf -= diff * suf_sum[i - 1]\n",
    "            ans = min(ans, pre + suf)\n",
    "        return ans"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "# change all nums into integer x, requires cost of\r\n",
    "# y(x) = sum(abs(nums[i] - x) * cost[i])\r\n",
    "#      = sumprod(nums[i], cost[i]) - x * sum(cost[i]) for all i, nums[i] <= x\r\n",
    "#      + x * sum(cost[j]) - sumprod(nums[j], cost[j]) for all j, nums[j] > x\r\n",
    "# precalculate presum of sumprod of nums and cost, and presum of cost\r\n",
    "# traverse all min(nums) <= x <= max(nums) to find global minimum\r\n",
    "pre_spd = [0] * 100001\r\n",
    "pre_sum = [0] * 100001\r\n",
    "class Solution:\r\n",
    "    def minCost(self, nums: List[int], cost: List[int]) -> int:\r\n",
    "        n = len(nums)\r\n",
    "        nc = sorted(zip(nums, cost))\r\n",
    "        for i in range(n):\r\n",
    "            pre_spd[i + 1] = pre_spd[i] + nc[i][0] * nc[i][1]\r\n",
    "            pre_sum[i + 1] = pre_sum[i] + nc[i][1]\r\n",
    "        \r\n",
    "        j = 0\r\n",
    "\r\n",
    "        def y(x: int) -> int:\r\n",
    "            nonlocal j\r\n",
    "            while j < n and nc[j][0] <= x:\r\n",
    "                j += 1\r\n",
    "            return x * (2 * pre_sum[j] - pre_sum[n]) + (pre_spd[n] - 2 * pre_spd[j])\r\n",
    "        \r\n",
    "        return min(map(y, range(nc[0][0], nc[-1][0] + 1)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        m = len(grid)\n",
    "        n = len(grid[0])\n",
    "        directions = [(0, 1), (0, -1), (1, 0), (-1, 0)] \n",
    "\n",
    "        cost = [[float('inf')] * n for _ in range(m)]\n",
    "        cost[0][0] = 0\n",
    "\n",
    "        queue = collections.deque([(0, 0, 0)]) \n",
    "        while queue:\n",
    "            i, j, length = queue.popleft()\n",
    "            for k in range(4):\n",
    "                i1=i+directions[k][0]\n",
    "                j1=j+directions[k][1]\n",
    "                if i1<=m-1 and j1<=n-1 and i1>=0 and j1>=0:\n",
    "                    if grid[i][j]==k+1:\n",
    "                        length=cost[i][j]\n",
    "                    else:\n",
    "                        length=cost[i][j]+1\n",
    "                    if(length<cost[i1][j1]):\n",
    "                        cost[i1][j1]=length\n",
    "                        queue.append([i1,j1,length])\n",
    "        return cost[m - 1][n - 1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "autodr = [[0,0], [0,1], [0, -1], [1, 0], [-1, 0]]\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        n, m = len(grid), len(grid[0])\n",
    "\n",
    "        cst = 0\n",
    "\n",
    "        dp = [[float('inf')] * m for _ in range(n)]\n",
    "        vis = [[1] * m for _ in range(n)]\n",
    "        dp[0][0] = 0\n",
    "\n",
    "        q = deque()\n",
    "        q.append((0,0))\n",
    "        while q:\n",
    "            cx, cy = q.popleft()\n",
    "            aflag = grid[cx][cy]\n",
    "            aanx, aany = cx + autodr[aflag][0], cy + autodr[aflag][1]\n",
    "\n",
    "            if 0<=aanx<n and 0<=aany<m and dp[cx][cy] < dp[aanx][aany]:\n",
    "                dp[aanx][aany] = dp[cx][cy]\n",
    "                q.append((aanx, aany))\n",
    "            \n",
    "            for i in range(1, 5):\n",
    "                if i != aflag:\n",
    "                    nx, ny = cx + autodr[i][0], cy + autodr[i][1]\n",
    "                    if 0<=nx<n and 0<=ny<m and dp[cx][cy] + 1 < dp[nx][ny]:\n",
    "                        dp[nx][ny] = dp[cx][cy] + 1\n",
    "                        q.append((nx, ny))\n",
    "        return dp[n-1][m-1]\n",
    "\n",
    "\n",
    "        return cst"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        m, n = len(grid), len(grid[0])\n",
    "        vis = [[0] * n for _ in range(m)]\n",
    "        Q= deque([(0, 0,0)])\n",
    "        D = [[float('inf')] * n for _ in range(m)]\n",
    "        D[0][0] = 0 \n",
    "        while Q:\n",
    "            d, x, y = Q.popleft() \n",
    "            if d > D[x][y]:\n",
    "                continue\n",
    "\n",
    "            for i, [nx, ny] in enumerate([[x, y+1], [x, y-1], [x+1, y], [x-1, y]]):\n",
    "                if 0<=nx<m and 0<=ny<n:\n",
    "                    nd = d + (0 if i + 1 == grid[x][y] else 1)\n",
    "                    if nd < D[nx][ny]:\n",
    "                        D[nx][ny] = nd \n",
    "                        Q.append((nd, nx, ny))\n",
    "        #print(D) \n",
    "        return D[m-1][n-1] "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from collections import deque\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        m = len(grid)\n",
    "        n = len(grid[0])\n",
    "        move = [0,(0,1),(0,-1),(1,0),(-1,0)]\n",
    "        dis = [[2147483647 for _ in range(n)] for _ in range(m)]\n",
    "        dis[0][0] = 0\n",
    "        deq = deque([(0,0,0)])\n",
    "        while deq:\n",
    "            i,j,w = deq.popleft()   \n",
    "            if i == m-1 and j == n-1:\n",
    "                return dis[i][j]\n",
    "            for c in range(1,5):\n",
    "                ti = i + move[c][0]\n",
    "                tj = j + move[c][1]\n",
    "                if 0 <= ti < m and 0 <= tj < n and dis[ti][tj] > w + (c != grid[i][j]):\n",
    "                    dis[ti][tj] = w + (c != grid[i][j])\n",
    "                    if c == grid[i][j]:\n",
    "                        deq.appendleft((ti,tj,dis[ti][tj]))\n",
    "                    else:\n",
    "                        deq.append((ti,tj,dis[ti][tj]))\n",
    "        \n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        R, C = len(grid), len(grid[0])\n",
    "        dist = [[inf] * C for r in range(R)]\n",
    "        dist[0][0] = 0\n",
    "        q = deque([(0, 0)])\n",
    "        directions = [[0, 1], [0, -1], [1, 0], [-1, 0]] # right, left, down, up\n",
    "        while q:\n",
    "            r, c = q.popleft()\n",
    "            for i, (dr, dc) in enumerate(directions):\n",
    "                row, col = r + dr, c + dc\n",
    "                if 0 <= row < R and 0 <= col < C:\n",
    "                    obstacle = i + 1 != grid[r][c]\n",
    "                    if obstacle + dist[r][c] < dist[row][col]:\n",
    "                        dist[row][col] = obstacle + dist[r][c]\n",
    "                        if not obstacle:\n",
    "                            q.appendleft((row, col))\n",
    "                        else:\n",
    "                            q.append((row, col))\n",
    "        return dist[-1][-1]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from collections import deque\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        m = len(grid)\n",
    "        n = len(grid[0])\n",
    "        move = [0,(0,1),(0,-1),(1,0),(-1,0)]\n",
    "        dis = [[2147483647 for _ in range(n)] for _ in range(m)]\n",
    "        dis[0][0] = 0\n",
    "        deq = deque([(0,0,0)])\n",
    "        while deq:\n",
    "            i,j,w = deq.popleft()   \n",
    "            for c in range(1,5):\n",
    "                ti = i + move[c][0]\n",
    "                tj = j + move[c][1]\n",
    "                if 0 <= ti < m and 0 <= tj < n and dis[ti][tj] > w + (c != grid[i][j]):\n",
    "                    dis[ti][tj] = w + (c != grid[i][j])\n",
    "                    if c == grid[i][j]:\n",
    "                        deq.appendleft((ti,tj,dis[ti][tj]))\n",
    "                    else:\n",
    "                        deq.append((ti,tj,dis[ti][tj]))\n",
    "        return dis[m-1][n-1]\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        move = [(0, 1), (0, -1), (1, 0), (-1, 0)]\n",
    "        m, n = len(grid), len(grid[0])\n",
    "        distence = [[inf] * n for _ in range(m)]\n",
    "        distence[0][0] = 0\n",
    "        q = deque([(0, 0)])\n",
    "        while q:\n",
    "            i, j = q.popleft()\n",
    "            if i == m - 1 and j == n - 1:\n",
    "                return distence[i][j]\n",
    "            for k, g in enumerate(move, 1):\n",
    "                x = i + g[0]\n",
    "                y = j + g[1]\n",
    "                weight = 0 if grid[i][j] == k else 1\n",
    "                if 0 <= x < m and 0 <= y < n and distence[i][j] + weight < distence[x][y]:\n",
    "                    distence[x][y] = distence[i][j] + weight\n",
    "                    if weight == 0:\n",
    "                        q.appendleft((x, y))\n",
    "                    else:\n",
    "                        q.append((x, y))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        m, n = len(grid), len(grid[0])\n",
    "        vis = [[False for j in range(n)] for i in range(m)]\n",
    "        q = deque()\n",
    "        q.append((0, 0, 0))\n",
    "        while q:\n",
    "            c, i, j = q.popleft()\n",
    "            if vis[i][j]:\n",
    "                continue\n",
    "            vis[i][j] = True\n",
    "            if i == m - 1 and j == n - 1:\n",
    "                return c\n",
    "            if j + 1 < n and not vis[i][j + 1]:\n",
    "                if grid[i][j] == 1:\n",
    "                    q.appendleft((c, i, j + 1))\n",
    "                else:\n",
    "                    q.append((c + 1, i, j + 1))\n",
    "\n",
    "            if j - 1 >= 0 and not vis[i][j - 1]:\n",
    "                if grid[i][j] == 2:\n",
    "                    q.appendleft((c, i, j - 1))\n",
    "                else:\n",
    "                    q.append((c + 1, i, j - 1))\n",
    "\n",
    "            if i + 1 < m and not vis[i + 1][j]:\n",
    "                if grid[i][j] == 3:\n",
    "                    q.appendleft((c, i + 1, j))\n",
    "                else:\n",
    "                    q.append((c + 1, i + 1, j))\n",
    "\n",
    "            if i - 1 >= 0 and not vis[i - 1][j]:\n",
    "                if grid[i][j] == 4:\n",
    "                    q.appendleft((c, i - 1, j))\n",
    "                else:\n",
    "                    q.append((c + 1, i - 1, j))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        m, n = len(grid), len(grid[0])\n",
    "        frontier = [(0, 0)]\n",
    "        state = [[0] * n for _ in range(m)]\n",
    "        state[0][0] = 2 # 0 for free, 1 for visited, 2 for frontier\n",
    "        step = 0\n",
    "        while True:\n",
    "            new_frontier = []\n",
    "            frontier = [(i, j) for (i, j) in frontier if state[i][j] == 2]\n",
    "            for i, j in frontier:\n",
    "                state[i][j] = 1\n",
    "            q = deque(frontier)\n",
    "            while len(q):\n",
    "                i, j = q.popleft()\n",
    "                if i == m - 1 and j == n - 1:\n",
    "                    return step\n",
    "                for ni, nj, expd in [(i - 1, j, 4), (i + 1, j, 3), (i, j - 1, 2), (i, j + 1, 1)]:\n",
    "                    if 0 <= ni < m and 0 <= nj < n and state[ni][nj] != 1:\n",
    "                        if expd == grid[i][j]:\n",
    "                            state[ni][nj] = 1\n",
    "                            q.append((ni, nj))\n",
    "                        elif state[ni][nj] == 0:\n",
    "                            state[ni][nj] = 2\n",
    "                            new_frontier.append((ni, nj))\n",
    "            frontier = new_frontier\n",
    "            step += 1\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        m, n = len(grid), len(grid[0])\n",
    "        vis = [[0] * n for _ in range(m)]\n",
    "        Q= deque([(0, 0,0)])\n",
    "        D = [[float('inf')] * n for _ in range(m)]\n",
    "        D[0][0] = 0 \n",
    "        while Q:\n",
    "            d, x, y = Q.popleft() \n",
    "            if d > D[x][y]:\n",
    "                continue\n",
    "            if (x, y) == (m-1, n-1):\n",
    "                return d \n",
    "            for i, [nx, ny] in enumerate([[x, y+1], [x, y-1], [x+1, y], [x-1, y]]):\n",
    "                if 0<=nx<m and 0<=ny<n:\n",
    "                    if i+1 == grid[x][y] and d < D[nx][ny]:\n",
    "                        D[nx][ny] = d \n",
    "                        Q.appendleft((d, nx, ny))\n",
    "                    elif d+1 < D[nx][ny]:\n",
    "                        D[nx][ny] = d+1\n",
    "                        Q.append((d+1, nx, ny)) \n",
    "        return -1 "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        m, n = len(grid), len(grid[0])\n",
    "        directions = [(0, 1), (0, -1), (1, 0), (-1, 0)]  # 右、左、下、上\n",
    "\n",
    "        distances = [[float('inf')] * n for _ in range(m)]\n",
    "        distances[0][0] = 0\n",
    "\n",
    "        queue = [(0, 0, 0)]  # (代价, 行号, 列号)\n",
    "\n",
    "        while queue:\n",
    "            cost, row, col = heapq.heappop(queue)\n",
    "\n",
    "            if row == m - 1 and col == n - 1:\n",
    "                return cost\n",
    "\n",
    "            if cost > distances[row][col]:\n",
    "                continue\n",
    "\n",
    "            for i, (dx, dy) in enumerate(directions):\n",
    "                new_row, new_col = row + dx, col + dy\n",
    "\n",
    "                if 0 <= new_row < m and 0 <= new_col < n:\n",
    "                    new_cost = cost + (1 if grid[row][col] != i + 1 else 0)\n",
    "                    if new_cost < distances[new_row][new_col]:\n",
    "                        distances[new_row][new_col] = new_cost\n",
    "                        heapq.heappush(queue, (new_cost, new_row, new_col))\n",
    "\n",
    "        return -1  # 无效路径"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from math import inf\n",
    "from typing import List\n",
    "\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        m, n = len(grid), len(grid[0])\n",
    "        cost = [[inf] * n for _ in range(m)]\n",
    "        cost[0][0] = 0\n",
    "        queue = [(0, 0)]\n",
    "        dirs = [(0, 1), (0, -1), (1, 0), (-1, 0)]\n",
    "        while queue:\n",
    "            x, y = queue.pop(0)\n",
    "            for i, (x1, y1) in enumerate(dirs):\n",
    "                x2, y2 = x + x1, y + y1\n",
    "                if x2 >= 0 and x2 < m and y2 >= 0 and y2 < n:\n",
    "                    g = 0 if i + 1 == grid[x][y] else 1\n",
    "                    newCost = cost[x][y] + g\n",
    "                    if newCost < cost[x2][y2]:\n",
    "                        cost[x2][y2] = newCost\n",
    "\n",
    "                        if g == 0:\n",
    "                            queue.insert(0, (x2, y2))\n",
    "                        else:\n",
    "                            queue.append((x2, y2))\n",
    "        return cost[-1][-1]\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        def check(gridVal, idx):\n",
    "            return idx + 1 != gridVal\n",
    "        R, C = len(grid), len(grid[0])\n",
    "        dist = [[inf] * C for r in range(R)]\n",
    "        dist[0][0] = 0\n",
    "        q = deque([(0, 0)])\n",
    "        directions = [[0, 1], [0, -1], [1, 0], [-1, 0]] # right, left, down, up\n",
    "        while q:\n",
    "            r, c = q.popleft()\n",
    "            for i, (dr, dc) in enumerate(directions):\n",
    "                row, col = r + dr, c + dc\n",
    "                if 0 <= row < R and 0 <= col < C:\n",
    "                    obstacle = check(grid[r][c], i)\n",
    "                    if obstacle + dist[r][c] < dist[row][col]:\n",
    "                        dist[row][col] = obstacle + dist[r][c]\n",
    "                        if not obstacle:\n",
    "                            q.appendleft((row, col))\n",
    "                        else:\n",
    "                            q.append((row, col))\n",
    "        return dist[-1][-1]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from collections import deque\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid):\n",
    "        # 格子的数值 :\n",
    "        # 1 右\n",
    "        # 2 左\n",
    "        # 3 下\n",
    "        # 4 上\n",
    "        #            0      1      2      3      4\n",
    "        move = [None, (0, 1), (0, -1), (1, 0), (-1, 0)]\n",
    "        m, n = len(grid), len(grid[0])\n",
    "        distance = [[float('inf')] * n for _ in range(m)]\n",
    "\n",
    "        q = deque()\n",
    "        q.appendleft([0, 0])\n",
    "        distance[0][0] = 0\n",
    "\n",
    "        while q:\n",
    "            x, y = q.popleft()\n",
    "\n",
    "            if x == m - 1 and y == n - 1:\n",
    "                return distance[x][y]\n",
    "\n",
    "            for i in range(1, 5):\n",
    "                nx, ny = x + move[i][0], y + move[i][1]\n",
    "                weight = 1 if grid[x][y] != i else 0\n",
    "\n",
    "                if 0 <= nx < m and 0 <= ny < n and distance[x][y] + weight < distance[nx][ny]:\n",
    "                    distance[nx][ny] = distance[x][y] + weight\n",
    "\n",
    "                    if weight == 0:\n",
    "                        q.appendleft([nx, ny])\n",
    "                    else:\n",
    "                        q.append([nx, ny])\n",
    "\n",
    "        return -1\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from math import inf\n",
    "from typing import List\n",
    "\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        m, n = len(grid), len(grid[0])\n",
    "        cost = [[inf] * n for _ in range(m)]\n",
    "        cost[0][0] = 0\n",
    "        dirs = [(0, 1), (0, -1), (1, 0), (-1, 0)]\n",
    "        queue = [(0, 0)]\n",
    "        while queue:\n",
    "            x, y = queue.pop(0)\n",
    "            for i, (x1, y1) in enumerate(dirs):\n",
    "                x2, y2 = x + x1, y + y1\n",
    "                if x2 >= 0 and x2 < m and y2 >= 0 and y2 < n:\n",
    "                    g = 0 if i + 1 == grid[x][y] else 1\n",
    "                    newCost = cost[x][y] + g\n",
    "                    if newCost < cost[x2][y2]:\n",
    "                        cost[x2][y2] = newCost\n",
    "\n",
    "                        if g == 0:\n",
    "                            queue.insert(0, (x2, y2))\n",
    "                        else:\n",
    "                            queue.append((x2, y2))\n",
    "        return cost[-1][-1]\n",
    "\n",
    "\n",
    "# class Solution:\n",
    "#     def minCost(self, grid: List[List[int]]) -> int:\n",
    "#         m, n = len(grid), len(grid[0])\n",
    "#         cost = [[inf] * n for _ in range(m)]\n",
    "#         cost[0][0] = 0\n",
    "#         queue = [(0, 0)]\n",
    "#         dirs = [(0, 1), (0, -1), (1, 0), (-1, 0)]\n",
    "#         while queue:\n",
    "#             x, y = queue.pop(0)\n",
    "#             for i, (x1, y1) in enumerate(dirs):\n",
    "#                 x2, y2 = x + x1, y + y1\n",
    "#                 if x2 >= 0 and x2 < m and y2 >= 0 and y2 < n:\n",
    "#                     g = 0 if i + 1 == grid[x][y] else 1\n",
    "#                     newCost = cost[x][y] + g\n",
    "#                     if newCost < cost[x2][y2]:\n",
    "#                         cost[x2][y2] = newCost\n",
    "\n",
    "#                         if g == 0:\n",
    "#                             queue.insert(0, (x2, y2))\n",
    "#                         else:\n",
    "#                             queue.append((x2, y2))\n",
    "#         return cost[-1][-1]\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        move = [(0, 1), (0, -1), (1, 0), (-1, 0)]\n",
    "        m, n = len(grid), len(grid[0])\n",
    "        distence = [[inf] * n for _ in range(m)]\n",
    "        distence[0][0] = 0\n",
    "        q = deque([(0, 0)])\n",
    "        vis = [[False]*n for _ in range(m)]\n",
    "        while q:\n",
    "            i, j = q.popleft()\n",
    "            if vis[i][j]:\n",
    "                continue\n",
    "            vis[i][j] = True\n",
    "            if i == m - 1 and j == n - 1:\n",
    "                return distence[i][j]\n",
    "            for k, g in enumerate(move, 1):\n",
    "                x = i + g[0]\n",
    "                y = j + g[1]\n",
    "                weight = 0 if grid[i][j] == k else 1\n",
    "                if 0 <= x < m and 0 <= y < n and distence[i][j] + weight < distence[x][y]:\n",
    "                    distence[x][y] = distence[i][j] + weight\n",
    "                    if weight == 0:\n",
    "                        q.appendleft((x, y))\n",
    "                    else:\n",
    "                        q.append((x, y))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "import heapq\n",
    "from collections import deque\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        m,n = len(grid),len(grid[0])\n",
    "        dist = [float('inf')]*(m*n)\n",
    "        dist[0] = 0\n",
    "        # visited = set()\n",
    "        queue = deque([(0,0)])\n",
    "\n",
    "        while queue:\n",
    "            x,y = queue.popleft()\n",
    "            # if (x,y) in visited:\n",
    "                # continue\n",
    "            # visited.add((x,y))\n",
    "            cur_pos = x*n + y\n",
    "            dx = [0,0,1,-1]\n",
    "            dy = [1,-1,0,0]\n",
    "            for i in range(4):\n",
    "                nx,ny = x+dx[i],y+dy[i]\n",
    "                n_pos = nx*n + ny\n",
    "                new_dist = dist[cur_pos] + (0 if grid[x][y]==i+1 else 1)\n",
    "                if 0<=nx<m and 0<=ny<n and new_dist<dist[n_pos]:\n",
    "                    dist[n_pos] = new_dist\n",
    "                    if grid[x][y] == i+1:\n",
    "                        queue.appendleft((nx,ny))\n",
    "                    else:\n",
    "                        queue.append((nx,ny))\n",
    "            pass\n",
    "        return dist[m*n-1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        m = len(grid)\n",
    "        n = len(grid[0])\n",
    "        direction = [None, [0, 1], [0, -1], [1, 0], [-1, 0]]\n",
    "        distance = [[10001 for i in range(n)] for j in range(m)]\n",
    "\n",
    "        que = deque()\n",
    "        que.append([0, 0])\n",
    "        distance[0][0] = 0\n",
    "\n",
    "        while que:\n",
    "            x, y = que.popleft()\n",
    "            if x == m-1 and y == n-1:\n",
    "                return distance[x][y]\n",
    "            for i in range(1, 5):\n",
    "                nx = x + direction[i][0]\n",
    "                ny = y + direction[i][1]\n",
    "                if grid[x][y] != i:\n",
    "                    w = 1\n",
    "                else:\n",
    "                    w = 0\n",
    "                if nx >= 0 and nx < m and ny >= 0 and ny < n and distance[x][y] + w < distance[nx][ny]:\n",
    "                    distance[nx][ny] = distance[x][y] + w\n",
    "                    if w == 0:\n",
    "                        que.appendleft([nx, ny])\n",
    "                    else:\n",
    "                        que.append([nx, ny])\n",
    "        return -1\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from collections import deque\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid):\n",
    "        # 格子的数值 :\n",
    "        # 1 右\n",
    "        # 2 左\n",
    "        # 3 下\n",
    "        # 4 上\n",
    "        #            0      1      2      3      4\n",
    "        move = [None, (0, 1), (0, -1), (1, 0), (-1, 0)]\n",
    "        m, n = len(grid), len(grid[0])\n",
    "        distance = [[float('inf')] * n for _ in range(m)]\n",
    "\n",
    "        q = deque()\n",
    "        q.appendleft([0, 0])\n",
    "        distance[0][0] = 0\n",
    "\n",
    "        while q:\n",
    "            x, y = q.popleft()\n",
    "\n",
    "            if x == m - 1 and y == n - 1:\n",
    "                return distance[x][y]\n",
    "\n",
    "            for i in range(1, 5):\n",
    "                nx, ny = x + move[i][0], y + move[i][1]\n",
    "                weight = 1 if grid[x][y] != i else 0\n",
    "\n",
    "                if 0 <= nx < m and 0 <= ny < n and distance[x][y] + weight < distance[nx][ny]:\n",
    "                    distance[nx][ny] = distance[x][y] + weight\n",
    "\n",
    "                    if weight == 0:\n",
    "                        q.appendleft([nx, ny])\n",
    "                    else:\n",
    "                        q.append([nx, ny])\n",
    "\n",
    "        return -1\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from collections import deque\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid):\n",
    "        # 格子的数值 :\n",
    "        # 1 右\n",
    "        # 2 左\n",
    "        # 3 下\n",
    "        # 4 上\n",
    "        #            0      1      2      3      4\n",
    "        move = [None, (0, 1), (0, -1), (1, 0), (-1, 0)]\n",
    "        m, n = len(grid), len(grid[0])\n",
    "        distance = [[float('inf')] * n for _ in range(m)]\n",
    "\n",
    "        q = deque()\n",
    "        q.appendleft([0, 0])\n",
    "        distance[0][0] = 0\n",
    "\n",
    "        while q:\n",
    "            x, y = q.popleft()\n",
    "\n",
    "            if x == m - 1 and y == n - 1:\n",
    "                return distance[x][y]\n",
    "\n",
    "            for i in range(1, 5):\n",
    "                nx, ny = x + move[i][0], y + move[i][1]\n",
    "                weight = 1 if grid[x][y] != i else 0\n",
    "\n",
    "                if 0 <= nx < m and 0 <= ny < n and distance[x][y] + weight < distance[nx][ny]:\n",
    "                    distance[nx][ny] = distance[x][y] + weight\n",
    "\n",
    "                    if weight == 0:\n",
    "                        q.appendleft([nx, ny])\n",
    "                    else:\n",
    "                        q.append([nx, ny])\n",
    "\n",
    "        return -1\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        m = len(grid)\n",
    "        n = len(grid[0])\n",
    "        q = deque()\n",
    "        distance = [[inf] * n for _ in range(m)]\n",
    "        distance[0][0] = 0\n",
    "        dire = [[0, 1], [0, -1], [1, 0], [-1, 0]]\n",
    "        q.append([0, 0])\n",
    "        while len(q):\n",
    "            x, y = q.popleft()\n",
    "            for k in range(4):\n",
    "                new_x = x + dire[k][0]\n",
    "                new_y = y + dire[k][1]\n",
    "                if 0 <= new_x < m and 0 <= new_y < n:\n",
    "                    cost = 0\n",
    "                    if k + 1 != grid[x][y]:\n",
    "                        cost = 1\n",
    "                    if cost + distance[x][y] < distance[new_x][new_y]:\n",
    "                        distance[new_x][new_y] = cost + distance[x][y]\n",
    "                        if cost == 0:\n",
    "                            q.appendleft([new_x, new_y])\n",
    "                        else:\n",
    "                            q.append([new_x, new_y])\n",
    "        return distance[m - 1][n - 1]\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "import heapq\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        m,n = len(grid),len(grid[0])\n",
    "        dist = [float('inf')]*(m*n)\n",
    "        dist[0] = 0\n",
    "        queue = [(0,0,0)]\n",
    "        while queue:\n",
    "            dis, x, y = heapq.heappop(queue)\n",
    "            cur_pos = n*x+y\n",
    "            if dist[cur_pos]<dis:\n",
    "                continue\n",
    "            dx = [0,0,1,-1]\n",
    "            dy = [1,-1,0,0]\n",
    "            for i in range(4):\n",
    "                nx, ny = x+dx[i], y+dy[i]\n",
    "                n_pos = nx*n+ny\n",
    "                if 0<=nx<m and 0<=ny<n:\n",
    "                    nextD = 0 if grid[x][y]==i+1 else 1\n",
    "                    if dis+nextD < dist[n_pos]:\n",
    "                        dist[n_pos] = dis+nextD\n",
    "                        heapq.heappush(queue, (dist[n_pos],nx,ny))\n",
    "        return dist[m*n-1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from collections import deque\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid):\n",
    "        move = [None, (0, 1), (0, -1), (1, 0), (-1, 0)]\n",
    "        m,n=len(grid),len(grid[0])\n",
    "        distance=[[float('inf')]* n for _ in range(m)]\n",
    "\n",
    "        q=deque()\n",
    "        q.appendleft([0,0])\n",
    "        distance[0][0]=0\n",
    "\n",
    "        while q:\n",
    "            x,y=q.popleft()\n",
    "\n",
    "            if x==m-1 and y ==n-1:\n",
    "                return distance[x][y]\n",
    "\n",
    "\n",
    "            for i in range(1,5):\n",
    "                nx,ny=x+move[i][0],y+move[i][1]\n",
    "                weight=1 if grid[x][y]!=i else 0\n",
    "\n",
    "                if 0 <= nx < m and 0 <= ny < n and distance[x][y] + weight < distance[nx][ny]:\n",
    "                    distance[nx][ny]=distance[x][y]+weight\n",
    "\n",
    "                    if weight==0:\n",
    "                        q.appendleft([nx,ny])\n",
    "                    else:\n",
    "                        q.append([nx,ny])\n",
    "\n",
    "        return -1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from collections import deque\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        move = [[], [0,1], [0,-1], [1,0], [-1,0]]\n",
    "        m = len(grid)\n",
    "        n = len(grid[0])\n",
    "        distance = [[100000 for _ in range(n)] for _ in range(m)]\n",
    "        queue = deque()\n",
    "        queue.append([0,0])\n",
    "        distance[0][0] = 0\n",
    "        while queue:\n",
    "            record = queue.popleft()\n",
    "            x = record[0]\n",
    "            y = record[1]\n",
    "            if x == m-1 and y == n-1:\n",
    "                return distance[x][y]\n",
    "            for i in range(1,5):\n",
    "                weight = 0 if i == grid[x][y] else 1\n",
    "                nx = x + move[i][0]\n",
    "                ny = y + move[i][1]\n",
    "                if nx >= 0 and nx < m and ny >= 0 and ny < n and distance[x][y] + weight < distance[nx][ny]:\n",
    "                    distance[nx][ny] = distance[x][y] + weight\n",
    "                    if weight == 0:\n",
    "                        queue.appendleft([nx, ny])\n",
    "                    else:\n",
    "                        queue.append([nx, ny])\n",
    "        return -1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from heapq import heapify, heappop, heappush\r\n",
    "dist = [[0] * 100 for _ in range(100)]\r\n",
    "neighbors = [(0, 1), (0, -1), (1, 0), (-1, 0)]\r\n",
    "\r\n",
    "class Solution:\r\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\r\n",
    "        m = len(grid)\r\n",
    "        n = len(grid[0])\r\n",
    "        for i in range(m):\r\n",
    "            for j in range(n):\r\n",
    "                dist[i][j] = -1\r\n",
    "        \r\n",
    "        hq: list[tuple[int, int, int]] = list()\r\n",
    "        heapify(hq)\r\n",
    "        heappush(hq, (0, 0, 0))\r\n",
    "        dist[0][0] = 0\r\n",
    "\r\n",
    "        while dist[m - 1][n - 1] == -1 or hq[0][0] < dist[m - 1][n - 1]:\r\n",
    "            d, i, j = heappop(hq)\r\n",
    "            for k, (a, b) in enumerate(neighbors):\r\n",
    "                if 0 <= i + a < m and 0 <= j + b < n:\r\n",
    "                    nxt = d + (1 if grid[i][j] != k + 1 else 0)\r\n",
    "                    if dist[i + a][j + b] == -1 or dist[i + a][j + b] > nxt:\r\n",
    "                        dist[i + a][j + b] = nxt\r\n",
    "                        heappush(hq, (nxt, i + a, j + b))\r\n",
    "        \r\n",
    "        return dist[m - 1][n - 1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "import heapq\n",
    "\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        m, n = len(grid), len(grid[0])\n",
    "        stack = [[0, 0, 0]]\n",
    "        heapq.heapify(stack)\n",
    "        while stack:\n",
    "            dis, i, j = heapq.heappop(stack)\n",
    "            if i == m - 1 and j == n - 1:\n",
    "                return dis\n",
    "            if not grid[i][j]:\n",
    "                continue\n",
    "            if j + 1 < n and grid[i][j + 1]:\n",
    "                heapq.heappush(stack, [dis + int(grid[i][j] != 1), i, j + 1])\n",
    "            if j - 1 >= 0 and grid[i][j - 1]:\n",
    "                heapq.heappush(stack, [dis + int(grid[i][j] != 2), i, j - 1])\n",
    "            if i + 1 < m and grid[i + 1][j]:\n",
    "                heapq.heappush(stack, [dis + int(grid[i][j] != 3), i + 1, j])\n",
    "            if i - 1 >= 0 and grid[i - 1][j]:\n",
    "                heapq.heappush(stack, [dis + int(grid[i][j] != 4), i - 1, j])\n",
    "            grid[i][j] = 0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        m, n = len(grid), len(grid[0])\n",
    "        \n",
    "        dirxy = [[0,1],[0,-1],[1,0],[-1,0]]\n",
    "        N = m*n\n",
    " \n",
    "\n",
    "        def dijkstra(s, dist):\n",
    "            vis = [0] * N \n",
    "            dist[s] = 0 \n",
    "            Q = [(dist[s], s)]\n",
    "            while Q:\n",
    "                d, u = heapq.heappop(Q)\n",
    "                if vis[u]:\n",
    "                    continue\n",
    "                vis[u] = 1\n",
    "                i,j = u//n, u%n \n",
    "                for k, [di, dj] in enumerate(dirxy):\n",
    "                    ni,nj = i + di, j + dj\n",
    "                    w = 0 if grid[i][j] == (k + 1) else 1\n",
    "                    if 0<=ni<m and 0<=nj<n:\n",
    "                        v = ni*n + nj \n",
    "                        if dist[v] > dist[u] + w:\n",
    "                            dist[v] = dist[u] + w\n",
    "                            heapq.heappush(Q,(dist[v],v))\n",
    "        \n",
    "        dist = [float('inf')] * N \n",
    "        dijkstra(0, dist)\n",
    "        return dist[N-1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from collections import defaultdict\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        total_row = len(grid)\n",
    "        total_line = len(grid[0])\n",
    "\n",
    "        distances = [0] + [float('inf') for _ in range(total_line*total_row-1)]\n",
    "        visited = [False for _ in range(total_row*total_line)]\n",
    "\n",
    "        priority_queue = [(0,0,0)]\n",
    "        # heapq.heapify(priority_queue)\n",
    "\n",
    "        while len(priority_queue) > 0:\n",
    "            curr_min_dis, x, y = heapq.heappop(priority_queue)\n",
    "            for i, (next_x, next_y) in enumerate([(x, y + 1), (x, y - 1), (x + 1, y), (x - 1, y)]):\n",
    "                new_index = next_x * total_line + next_y\n",
    "                new_dis = distances[x*total_line+y] + (1 if grid[x][y] != i+1 else 0)\n",
    "\n",
    "                if 0<= next_x < total_row and 0<= next_y < total_line and new_dis < distances[new_index]:\n",
    "                    distances[new_index] = new_dis\n",
    "                    heapq.heappush(priority_queue, (new_dis, next_x, next_y))\n",
    "        \n",
    "        return distances[total_line*total_row-1]\n",
    "\n",
    "        \n",
    "\n",
    "\n",
    "class Node:\n",
    "    def __init__(self, val:int):\n",
    "        self.val = val\n",
    "        self.next = None"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from collections import defaultdict\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        total_row = len(grid)\n",
    "        total_line = len(grid[0])\n",
    "\n",
    "        distances = [0] + [float('inf') for _ in range(total_line*total_row-1)]\n",
    "        visited = [False for _ in range(total_row*total_line)]\n",
    "\n",
    "        priority_queue = [(0,0,0)]\n",
    "        heapq.heapify(priority_queue)\n",
    "\n",
    "        while len(priority_queue) > 0:\n",
    "            curr_min_dis, x, y = heapq.heappop(priority_queue)\n",
    "            for i, (next_x, next_y) in enumerate([(x, y + 1), (x, y - 1), (x + 1, y), (x - 1, y)]):\n",
    "                new_index = next_x * total_line + next_y\n",
    "                new_dis = distances[x*total_line+y] + (1 if grid[x][y] != i+1 else 0)\n",
    "\n",
    "                if 0<= next_x < total_row and 0<= next_y < total_line and new_dis < distances[new_index]:\n",
    "                    distances[new_index] = new_dis\n",
    "                    heapq.heappush(priority_queue, (new_dis, next_x, next_y))\n",
    "        \n",
    "        return distances[total_line*total_row-1]\n",
    "\n",
    "        \n",
    "\n",
    "\n",
    "class Node:\n",
    "    def __init__(self, val:int):\n",
    "        self.val = val\n",
    "        self.next = None"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "import heapq as hq\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        m=len(grid)\n",
    "        n=len(grid[0])\n",
    "        directions=[(0,1),(0,-1),(1,0),(-1,0)]\n",
    "        heap=[]\n",
    "        hq.heappush(heap,[0,0,0])\n",
    "        vis=[[0]*n for _ in range(m)]\n",
    "        while heap:\n",
    "            d,x,y =hq.heappop(heap)\n",
    "            #print(d,x,y)\n",
    "            if x==m-1 and y==n-1:\n",
    "                return d\n",
    "            if vis[x][y]==1:\n",
    "                continue\n",
    "            vis[x][y]=1\n",
    "\n",
    "            for d0,d1 in [(0,1),(0,-1),(1,0),(-1,0)]:\n",
    "                x1=x+d0\n",
    "                y1=y+d1\n",
    "               # \n",
    "                if 0<=x1<m and 0<=y1<n and vis[x1][y1]==0:\n",
    "                   # print(x1,y1)\n",
    "                    if (d0,d1)==directions[grid[x][y]-1]:\n",
    "                        hq.heappush(heap,[d,x1,y1])\n",
    "                    else:\n",
    "                        hq.heappush(heap,[d+1,x1,y1])\n",
    "\n",
    "        return -1\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        n,m = len(grid),len(grid[0])\n",
    "        dir_ = {1:(0,1),2:(0,-1),3:(1,0),4:(-1,0)}\n",
    "        h = [[0,0,0]]\n",
    "        dis = [[float('inf') for _ in range(m)] for _ in range(n)]\n",
    "        dis[0][0] = 0\n",
    "        while h:\n",
    "            d,x,y = heappop(h)\n",
    "            if d > dis[x][y]:\n",
    "                continue\n",
    "            for i in range(1,5):\n",
    "                dx,dy = dir_[i]\n",
    "                nx,ny = x + dx,y + dy\n",
    "                if nx < 0 or nx >= n or ny < 0 or ny >= m:\n",
    "                    continue\n",
    "                nc = d + 1 if i != grid[x][y] else d\n",
    "                if nc < dis[nx][ny]:\n",
    "                    dis[nx][ny] = nc\n",
    "                    heappush(h,[nc,nx,ny])\n",
    "\n",
    "        return dis[n - 1][m - 1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "from typing import *\n",
    "from math import *\n",
    "from functools import cache\n",
    "from queue import *\n",
    "from heapq import *\n",
    "from bisect import bisect_left\n",
    "# start-----------------------------------------------------\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        m,n = len(grid), len(grid[0])\n",
    "        dx = [0,0,0,1,-1]\n",
    "        dy = [0,1,-1,0,0]\n",
    "        dist = [inf] * (m * n)\n",
    "        seen = [False] * (m * n)\n",
    "        dist[0] = 0\n",
    "        pq = PriorityQueue()\n",
    "        pq.put((0, 0))\n",
    "\n",
    "        while not pq.empty():\n",
    "            cur_dis,cur_pos = pq.get()\n",
    "            if seen[cur_pos]:\n",
    "                continue\n",
    "            seen[cur_pos] = True\n",
    "            for i in range(1, 5):\n",
    "                x, y = cur_pos // n, cur_pos % n\n",
    "                nx, ny = x + dx[i], y + dy[i]\n",
    "                new_dis, new_pos = cur_dis + (i != grid[x][y]), nx * n + ny\n",
    "                if nx >= 0 and nx < m and ny >= 0 and ny < n and new_dis < dist[new_pos]:\n",
    "                    dist[new_pos] = new_dis\n",
    "                    pq.put((new_dis, new_pos))                    \n",
    "        return dist[m * n - 1]\n",
    "s = Solution()\n",
    "s.minCost([[4]])\n",
    "# end-------------------------------------------------------\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "\n",
    "        m, n = len(grid), len(grid[0])\n",
    "        N = m * n \n",
    "        dist = [float('inf')] * N \n",
    "        def dijkstra(s, dist):\n",
    "            vis = [0] * N \n",
    "            dist[s] = 0\n",
    "            Q = [(dist[s], s)]\n",
    "            while Q:\n",
    "                d, u = heapq.heappop(Q)\n",
    "                if vis[u]:\n",
    "                    continue \n",
    "                vis[u]= 1\n",
    "                i,j = u//n, u % n \n",
    "                for k, [di,dj] in enumerate([[0,1],[0,-1],[1,0],[-1,0]]):\n",
    "                    ni,nj = i+di, j + dj \n",
    "                    if 0 <= ni < m and 0<= nj < n:\n",
    "                        v = ni * n + nj \n",
    "                        ii = 0 if grid[i][j] == (k+1) else 1 \n",
    "                        if dist[v] > dist[u] + ii:\n",
    "                            dist[v] = dist[u] + ii \n",
    "                            heapq.heappush(Q, (dist[v], v))\n",
    "        dijkstra(0, dist)\n",
    "        return dist[N-1]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        import heapq\n",
    "        ref = [(0,0),(0,1),(0,-1),(1,0),(-1,0)]\n",
    "        \n",
    "        n=len(grid)\n",
    "        m=len(grid[0])\n",
    "        vis = [[False]*m for _ in range(n)]\n",
    "        dis_g = [[float('inf') for _ in range(m)] for _ in range(n)]\n",
    "        queue = [(0,(0,0))]\n",
    "        vis[0][0]=True\n",
    "        heapq.heapify(queue)\n",
    "\n",
    "        while queue:\n",
    "            dis,cur = heapq.heappop(queue)\n",
    "            curx,cury = cur\n",
    "            if curx==n-1 and cury==m-1:\n",
    "                return dis\n",
    "            for i in range(1,5):\n",
    "                x,y=ref[i]\n",
    "                nextx = curx+x\n",
    "                nexty = cury+y\n",
    "                if 0<=nextx<n and 0<=nexty<m and vis[nextx][nexty]==False:\n",
    "                    if i!=grid[curx][cury]:\n",
    "                        new_dis = dis+1\n",
    "                    else:\n",
    "                        new_dis = dis\n",
    "\n",
    "                    if new_dis>=dis_g[nextx][nexty]:\n",
    "                        continue\n",
    "                    dis_g[nextx][nexty] = new_dis\n",
    "                    heapq.heappush(queue, (new_dis,(nextx,nexty)))\n",
    "                    vis[nextx][nexty]==True\n",
    "            # print(cur)\n",
    "            # for l in dis_g:\n",
    "            #     print(l)\n",
    "            # print('==========================')\n",
    "        return -1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        import heapq\n",
    "        ref = [(0,0),(0,1),(0,-1),(1,0),(-1,0)]\n",
    "        \n",
    "        n=len(grid)\n",
    "        m=len(grid[0])\n",
    "        vis = [[False]*m for _ in range(n)]\n",
    "        dis_g = [[float('inf') for _ in range(m)] for _ in range(n)]\n",
    "        queue = [(0,(0,0))]\n",
    "        vis[0][0]=True\n",
    "        heapq.heapify(queue)\n",
    "\n",
    "        while queue:\n",
    "            dis,cur = heapq.heappop(queue)\n",
    "            curx,cury = cur\n",
    "            if curx==n-1 and cury==m-1:\n",
    "                return dis\n",
    "            for i in range(1,5):\n",
    "                x,y=ref[i]\n",
    "                nextx = curx+x\n",
    "                nexty = cury+y\n",
    "                if 0<=nextx<n and 0<=nexty<m and vis[nextx][nexty]==False:\n",
    "                    if i!=grid[curx][cury]:\n",
    "                        new_dis = dis+1\n",
    "                    else:\n",
    "                        new_dis = dis\n",
    "\n",
    "                    if new_dis>=dis_g[nextx][nexty]:\n",
    "                        continue\n",
    "                    dis_g[nextx][nexty] = new_dis\n",
    "                    heapq.heappush(queue, (new_dis,(nextx,nexty)))\n",
    "                    vis[nextx][nexty]==True\n",
    "            # print(cur)\n",
    "            # for l in dis_g:\n",
    "            #     print(l)\n",
    "            # print('==========================')\n",
    "        return -1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        import heapq\n",
    "        ref = [(0,0),(0,1),(0,-1),(1,0),(-1,0)]\n",
    "        \n",
    "        n=len(grid)\n",
    "        m=len(grid[0])\n",
    "        vis = [[False]*m for _ in range(n)]\n",
    "        dis_g = [[float('inf') for _ in range(m)] for _ in range(n)]\n",
    "        queue = [(0,(0,0))]\n",
    "        vis[0][0]=True\n",
    "        heapq.heapify(queue)\n",
    "\n",
    "        while queue:\n",
    "            dis,cur = heapq.heappop(queue)\n",
    "            curx,cury = cur\n",
    "            if curx==n-1 and cury==m-1:\n",
    "                return dis\n",
    "            for i in range(1,5):\n",
    "                x,y=ref[i]\n",
    "                nextx = curx+x\n",
    "                nexty = cury+y\n",
    "                if 0<=nextx<n and 0<=nexty<m and vis[nextx][nexty]==False:\n",
    "                    if i!=grid[curx][cury]:\n",
    "                        new_dis = dis+1\n",
    "                    else:\n",
    "                        new_dis = dis\n",
    "\n",
    "                    if new_dis>=dis_g[nextx][nexty]:\n",
    "                        continue\n",
    "                    dis_g[nextx][nexty] = new_dis\n",
    "                    heapq.heappush(queue, (new_dis,(nextx,nexty)))\n",
    "                    vis[nextx][nexty]==True\n",
    "            # print(cur)\n",
    "            # for l in dis_g:\n",
    "            #     print(l)\n",
    "            # print('==========================')\n",
    "        return -1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        m, n = len(grid), len(grid[0])\n",
    "        dirs = [(0, 1), (0, -1), (1, 0), (-1, 0)]\n",
    "        q = deque()\n",
    "        visited = set()\n",
    "        q.append((0, 0, 0))\n",
    "        while len(q):\n",
    "            r, c, step = q.popleft()\n",
    "            visited.add((r, c))\n",
    "            if r==m-1 and c==n-1:\n",
    "                return step\n",
    "            for idx, d in enumerate(dirs):\n",
    "                cur_cost = 0 if (idx == grid[r][c]-1) else 1\n",
    "                new_r, new_c = r+d[0], c+d[1]\n",
    "                if 0<=new_r<m and 0<=new_c<n and (new_r, new_c) not in visited:\n",
    "                    if cur_cost == 0:\n",
    "                        q.appendleft((new_r, new_c, step))\n",
    "                    else:\n",
    "                        q.append((new_r, new_c, step+cur_cost))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        dir = [[-1, 0, 3], [1, 0, 4], [0, -1, 1], [0, 1, 2]]\n",
    "        r, c = len(grid), len(grid[0])\n",
    "        dq1 = deque([[r - 1, c - 1]])\n",
    "        dp = [[inf] * c for _ in range(r)]\n",
    "        dp[r - 1][c - 1] = 0\n",
    "        dq3, tmp = deque(), {}\n",
    "        while dq1:\n",
    "            dq2 = deque()\n",
    "            # print(dq1)\n",
    "            while dq1:\n",
    "                x, y = dq1.popleft()\n",
    "                for d1, d2, d in dir:\n",
    "                    u, v = x + d1, y + d2\n",
    "                    if 0 <= u < r and 0 <= v < c:\n",
    "                        if dp[u][v] != inf: continue\n",
    "                        if d == grid[u][v]:\n",
    "                            dp[u][v] = dp[x][y]\n",
    "                            dq2.append([u, v])\n",
    "                        elif (u, v) not in tmp:\n",
    "                            dq3.append([u, v])\n",
    "                            tmp[(u, v)] = dp[x][y] + 1\n",
    "            if dq2:\n",
    "                dq1 = dq2\n",
    "            else:\n",
    "                for (x, y), v in tmp.items():\n",
    "                    dp[x][y] = v\n",
    "                dq1, dq3, tmp = dq3, deque(), {}\n",
    "            if dp[0][0] != inf:\n",
    "                return dp[0][0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        m, n = len(grid), len(grid[0])\n",
    "        BIG = int(1e9)\n",
    "        dist = [0] + [BIG] * (m * n - 1)\n",
    "        seen = set()\n",
    "        q = collections.deque([(0, 0)])\n",
    "\n",
    "        while len(q) > 0:\n",
    "            x, y = q.popleft()\n",
    "            if (x, y) in seen:\n",
    "                continue\n",
    "            seen.add((x, y))\n",
    "            cur_pos = x * n + y\n",
    "            for i, (nx, ny) in enumerate([(x, y + 1), (x, y - 1), (x + 1, y), (x - 1, y)]):\n",
    "                new_pos = nx * n + ny\n",
    "                new_dis = dist[cur_pos] + (1 if grid[x][y] != i + 1 else 0)\n",
    "                if 0 <= nx < m and 0 <= ny < n and new_dis < dist[new_pos]:\n",
    "                    dist[new_pos] = new_dis\n",
    "                    if grid[x][y] == i + 1:\n",
    "                        q.appendleft((nx, ny))\n",
    "                    else:\n",
    "                        q.append((nx, ny))\n",
    "        \n",
    "        return dist[m * n - 1]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        m, n = len(grid), len(grid[0])\n",
    "        dist = [0] + [inf]*(m*n-1)\n",
    "        seen = set()\n",
    "        q = deque([(0, 0)])\n",
    "        \n",
    "        while q:\n",
    "            x, y = q.popleft()\n",
    "            if (x, y) in seen:\n",
    "                continue\n",
    "            seen.add((x, y))\n",
    "            now = x * n + y\n",
    "            for i, (a, b) in enumerate([(x, y+1), (x, y-1), (x+1, y), (x-1, y)]):\n",
    "                nex = a * n + b\n",
    "                nex_dist = dist[now] + int(grid[x][y] != i+1)\n",
    "                if 0 <= a < m and 0 <= b < n and nex_dist < dist[nex]:\n",
    "                    dist[nex] = nex_dist\n",
    "                    if grid[x][y] == i + 1:\n",
    "                        q.appendleft((a, b))\n",
    "                    else:\n",
    "                        q.append((a, b))\n",
    "        return dist[-1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        m, n = len(grid), len(grid[0])\n",
    "        BIG = int(1e9)\n",
    "        dist = [0] + [BIG] * (m * n - 1)\n",
    "        seen = set()\n",
    "        q = collections.deque([(0, 0)])\n",
    "\n",
    "        while len(q) > 0:\n",
    "            x, y = q.popleft()\n",
    "            if (x, y) in seen:\n",
    "                continue\n",
    "            seen.add((x, y))\n",
    "            cur_pos = x * n + y\n",
    "            for i, (nx, ny) in enumerate([(x, y + 1), (x, y - 1), (x + 1, y), (x - 1, y)]):\n",
    "                new_pos = nx * n + ny\n",
    "                new_dis = dist[cur_pos] + (1 if grid[x][y] != i + 1 else 0)\n",
    "                if 0 <= nx < m and 0 <= ny < n and new_dis < dist[new_pos]:\n",
    "                    dist[new_pos] = new_dis\n",
    "                    if grid[x][y] == i + 1:\n",
    "                        q.appendleft((nx, ny))\n",
    "                    else:\n",
    "                        q.append((nx, ny))\n",
    "        \n",
    "        return dist[m * n - 1]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        dif=[[0,0],[0,1],[0,-1],[1,0],[-1,0]]\n",
    "        q=deque([(0,0)])\n",
    "        row,col=len(grid),len(grid[0])\n",
    "        dis=[[inf]*col for i in range(row)]\n",
    "        dis[0][0]=0\n",
    "        vis=set()\n",
    "        while q:\n",
    "            x,y=q.popleft()\n",
    "            if (x,y) in vis:continue\n",
    "            vis.add((x,y))\n",
    "            for i in range(1,5):\n",
    "                nx,ny=x+dif[i][0],y+dif[i][1]\n",
    "                n_dis=dis[x][y]+(0 if i==grid[x][y] else 1)\n",
    "                if 0<=nx<row and 0<=ny<col:\n",
    "                    if n_dis<dis[nx][ny]:\n",
    "                        dis[nx][ny]=n_dis\n",
    "                        if i==grid[x][y]:q.appendleft((nx,ny))\n",
    "                        else:q.append((nx,ny))\n",
    "        return dis[row-1][col-1]\n",
    "\n",
    "\n",
    "        \n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "        # m, n = len(grid), len(grid[0])\n",
    "        # dp = [[float('inf') for _ in range(n)] for _ in range(m)]\n",
    "        # q = []\n",
    "        # heapq.heappush(q, (0, 0, 0))\n",
    "        # dp[0][0] = 0\n",
    "        # dirs = [(0, 1),(0, -1),(1, 0),(-1, 0)]\n",
    "        # seen = set()\n",
    "        # while q:\n",
    "        #     dist, x, y = heapq.heappop(q)\n",
    "        #     if (x, y) in seen:\n",
    "        #         continue\n",
    "        #     if x == m - 1 and y == n - 1: # 广度优先遍历中最先到达的一定是最短路\n",
    "        #         return dist\n",
    "        #     seen.add((x, y))\n",
    "        #     for i, di in enumerate(dirs):\n",
    "        #         curx, cury = di[0] + x, di[1] + y\n",
    "        #         temp = 0 if i + 1 == grid[x][y] else 1\n",
    "        #         ans = temp + dist\n",
    "        #         if 0 <= curx < m and 0 <= cury < n and ans < dp[curx][cury]:\n",
    "        #             dp[curx][cury] = ans\n",
    "        #             heappush(q, (ans, curx, cury))\n",
    "        # return dp[-1][-1]\n",
    "                    \n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        m, n = len(grid), len(grid[0])\n",
    "        dp = [[float('inf') for _ in range(n)] for _ in range(m)]\n",
    "        q = []\n",
    "        heapq.heappush(q, (0, 0, 0))\n",
    "        dp[0][0] = 0\n",
    "        dirs = [(0, 1),(0, -1),(1, 0),(-1, 0)]\n",
    "        seen = set()\n",
    "        while q:\n",
    "            dist, x, y = heapq.heappop(q)\n",
    "            if (x, y) in seen:\n",
    "                continue\n",
    "            if x == m - 1 and y == n - 1:\n",
    "                return dist\n",
    "            seen.add((x, y))\n",
    "            for i, di in enumerate(dirs):\n",
    "                curx, cury = di[0] + x, di[1] + y\n",
    "                temp = 0 if i + 1 == grid[x][y] else 1\n",
    "                ans = temp + dist\n",
    "                if 0 <= curx < m and 0 <= cury < n and ans < dp[curx][cury]:\n",
    "                    dp[curx][cury] = ans\n",
    "                    heappush(q, (ans, curx, cury))\n",
    "        return dp[-1][-1]\n",
    "                    \n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        m, n = len(grid), len(grid[0])\n",
    "        BIG = int(1e9)\n",
    "        dist = [0] + [BIG] * (m * n - 1)\n",
    "        seen = set()\n",
    "        q = [(0, 0, 0)]\n",
    "\n",
    "        while len(q) > 0:\n",
    "            cur_dis, x, y = heapq.heappop(q)\n",
    "            if (x, y) in seen:\n",
    "                continue\n",
    "            seen.add((x, y))\n",
    "            cur_pos = x * n + y\n",
    "            for i, (nx, ny) in enumerate([(x, y + 1), (x, y - 1), (x + 1, y), (x - 1, y)]):\n",
    "                new_pos = nx * n + ny\n",
    "                new_dis = dist[cur_pos] + (1 if grid[x][y] != i + 1 else 0)\n",
    "                if 0 <= nx < m and 0 <= ny < n and new_dis < dist[new_pos]:\n",
    "                    dist[new_pos] = new_dis\n",
    "                    heapq.heappush(q, (new_dis, nx, ny))\n",
    "        \n",
    "        return dist[m * n - 1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        m, n = len(grid), len(grid[0])\n",
    "        count = 0\n",
    "        q = [(0, 0)]\n",
    "        vis = {(0, 0)}\n",
    "        dir = [(0, 1), (0, -1), (1, 0), (-1, 0)]\n",
    "        while True:\n",
    "            for i, j in q:\n",
    "                dx, dy = dir[grid[i][j]-1]\n",
    "                x, y = i+dx, j+dy\n",
    "                if 0<=x<m and 0<=y<n and (x,y) not in vis:\n",
    "                    q.append((x,y))\n",
    "                    vis.add((x,y))\n",
    "\n",
    "            if (m-1, n-1) in vis:\n",
    "                return count\n",
    "\n",
    "            count += 1\n",
    "\n",
    "            new_q = []\n",
    "            for i,j in q:\n",
    "                for dx, dy in dir:\n",
    "                    x, y = i+dx, j+dy \n",
    "                    if 0<=x<m and 0<=y<n and (x,y) not in vis:\n",
    "                        new_q.append((x,y))\n",
    "                        vis.add((x,y))\n",
    "            q = new_q"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        m, n = len(grid), len(grid[0])\n",
    "        BIG = int(1e9)\n",
    "        dist = [0] + [BIG] * (m * n - 1)\n",
    "        seen = set()\n",
    "        q = collections.deque([(0, 0)])\n",
    "\n",
    "        while len(q) > 0:\n",
    "            x, y = q.popleft()\n",
    "            if (x, y) in seen:\n",
    "                continue\n",
    "            seen.add((x, y))\n",
    "            cur_pos = x * n + y\n",
    "            for i, (nx, ny) in enumerate([(x, y + 1), (x, y - 1), (x + 1, y), (x - 1, y)]):\n",
    "                new_pos = nx * n + ny\n",
    "                new_dis = dist[cur_pos] + (1 if grid[x][y] != i + 1 else 0)\n",
    "                if 0 <= nx < m and 0 <= ny < n and new_dis < dist[new_pos]:\n",
    "                    dist[new_pos] = new_dis\n",
    "                    if grid[x][y] == i + 1:\n",
    "                        q.appendleft((nx, ny))\n",
    "                    else:\n",
    "                        q.append((nx, ny))\n",
    "        \n",
    "        return dist[m * n - 1]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    # 0-1 bfs\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        m, n = len(grid), len(grid[0])\n",
    "        BIG = int(1e9)\n",
    "        dist = [0] + [BIG] * (m * n - 1)\n",
    "        seen = set()\n",
    "        q = collections.deque([(0, 0)])\n",
    "\n",
    "        while len(q) > 0:\n",
    "            x, y = q.popleft()\n",
    "            if (x, y) in seen:\n",
    "                continue\n",
    "            seen.add((x, y))\n",
    "            cur_pos = x * n + y\n",
    "            for i, (nx, ny) in enumerate([(x, y + 1), (x, y - 1), (x + 1, y), (x - 1, y)]):\n",
    "                new_pos = nx * n + ny\n",
    "                new_dis = dist[cur_pos] + (1 if grid[x][y] != i + 1 else 0)\n",
    "                if 0 <= nx < m and 0 <= ny < n and new_dis < dist[new_pos]:\n",
    "                    dist[new_pos] = new_dis\n",
    "                    if grid[x][y] == i + 1:\n",
    "                        q.appendleft((nx, ny))\n",
    "                    else:\n",
    "                        q.append((nx, ny))\n",
    "        \n",
    "        return dist[m * n - 1]\n",
    "\n",
    "    # Dijkstra 算法\n",
    "    def minCost2(self, grid: List[List[int]]) -> int:\n",
    "        m, n = len(grid), len(grid[0])\n",
    "        BIG = int(1e9)\n",
    "        dist = [0] + [BIG] * (m * n - 1)\n",
    "        seen = set()\n",
    "        q = [(0, 0, 0)]\n",
    "\n",
    "        while len(q) > 0:\n",
    "            cur_dis, x, y = heapq.heappop(q)\n",
    "            if (x, y) in seen:\n",
    "                continue\n",
    "            seen.add((x, y))\n",
    "            cur_pos = x * n + y\n",
    "            for i, (nx, ny) in enumerate([(x, y + 1), (x, y - 1), (x + 1, y), (x - 1, y)]):\n",
    "                new_pos = nx * n + ny\n",
    "                new_dis = dist[cur_pos] + (1 if grid[x][y] != i + 1 else 0)\n",
    "                if 0 <= nx < m and 0 <= ny < n and new_dis < dist[new_pos]:\n",
    "                    dist[new_pos] = new_dis\n",
    "                    heapq.heappush(q, (new_dis, nx, ny))\n",
    "        \n",
    "        return dist[m * n - 1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        m, n = len(grid), len(grid[0])\n",
    "        q = deque([])\n",
    "        q.append((0, 0))\n",
    "        seen = set()\n",
    "        dirs = [(0, 1), (0, -1), (1, 0), (-1, 0)]\n",
    "        dp = [[float('inf') for _ in range(n)] for _ in range(m)]\n",
    "        dp[0][0] = 0\n",
    "        while q:\n",
    "            x, y = q.popleft()\n",
    "            if (x, y) in seen:\n",
    "                continue\n",
    "            # if x == m - 1 and y == n - 1:\n",
    "            #     return dist\n",
    "            seen.add((x, y))\n",
    "            for i, di in enumerate(dirs):\n",
    "                curx, cury = di[0] + x, di[1] + y\n",
    "                if 0 <= curx < m and 0 <= cury < n:\n",
    "                    num = (0 if i + 1 == grid[x][y] else 1)\n",
    "                    dist = dp[x][y]\n",
    "                    if dp[curx][cury] > dist + num:\n",
    "                        dp[curx][cury] = dist + num\n",
    "                        if num:\n",
    "                            q.append((curx, cury))\n",
    "                        else:\n",
    "                            q.appendleft((curx, cury))\n",
    "        return dp[-1][-1]\n",
    "        \n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "        # m, n = len(grid), len(grid[0])\n",
    "        # dp = [[float('inf') for _ in range(n)] for _ in range(m)]\n",
    "        # q = []\n",
    "        # heapq.heappush(q, (0, 0, 0))\n",
    "        # dp[0][0] = 0\n",
    "        # dirs = [(0, 1),(0, -1),(1, 0),(-1, 0)]\n",
    "        # seen = set()\n",
    "        # while q:\n",
    "        #     dist, x, y = heapq.heappop(q)\n",
    "        #     if (x, y) in seen:\n",
    "        #         continue\n",
    "        #     if x == m - 1 and y == n - 1: # 广度优先遍历中最先到达的一定是最短路\n",
    "        #         return dist\n",
    "        #     seen.add((x, y))\n",
    "        #     for i, di in enumerate(dirs):\n",
    "        #         curx, cury = di[0] + x, di[1] + y\n",
    "        #         temp = 0 if i + 1 == grid[x][y] else 1\n",
    "        #         ans = temp + dist\n",
    "        #         if 0 <= curx < m and 0 <= cury < n and ans < dp[curx][cury]:\n",
    "        #             dp[curx][cury] = ans\n",
    "        #             heappush(q, (ans, curx, cury))\n",
    "        # return dp[-1][-1]\n",
    "                    \n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        m, n = len(grid), len(grid[0])\n",
    "        dp = [[float('inf') for _ in range(n)] for _ in range(m)]\n",
    "        q = []\n",
    "        heapq.heappush(q, (0, 0, 0))\n",
    "        dp[0][0] = 0\n",
    "        dirs = [(0, 1),(0, -1),(1, 0),(-1, 0)]\n",
    "        seen = set()\n",
    "        while q:\n",
    "            dist, x, y = heapq.heappop(q)\n",
    "            if (x, y) in seen:\n",
    "                continue\n",
    "            if x == m - 1 and y == n - 1:\n",
    "                return dist\n",
    "            seen.add((x, y))\n",
    "            for i, di in enumerate(dirs):\n",
    "                curx, cury = di[0] + x, di[1] + y\n",
    "                temp = 0 if i + 1 == grid[x][y] else 1\n",
    "                ans = temp + dist\n",
    "                if 0 <= curx < m and 0 <= cury < n and ans < dp[curx][cury]:\n",
    "                    dp[curx][cury] = ans\n",
    "                    heappush(q, (ans, curx, cury))\n",
    "        return dp[-1][-1]\n",
    "                    \n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        m, n = len(grid), len(grid[0])\n",
    "        vis = [[0] * n for _ in range(m)]\n",
    "        Q= deque([(0, 0,0)])\n",
    "        while Q:\n",
    "            d, x, y = Q.popleft() \n",
    "            if vis[x][y]:\n",
    "                continue \n",
    "            vis[x][y] = 1\n",
    "            if (x, y) == (m-1, n-1):\n",
    "                return d \n",
    "            for i, [nx, ny] in enumerate([[x, y+1], [x, y-1], [x+1, y], [x-1, y]]):\n",
    "                if 0<=nx<m and 0<=ny<n:\n",
    "                    if i+1 == grid[x][y]:\n",
    "                        Q.appendleft((d, nx, ny))\n",
    "                    else:\n",
    "                        Q.append((d+1, nx, ny)) \n",
    "        return -1 "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "import heapq\n",
    "from collections import deque\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        m,n = len(grid),len(grid[0])\n",
    "        dist = [float('inf')]*(m*n)\n",
    "        dist[0] = 0\n",
    "        visited = set()\n",
    "        queue = deque([(0,0)])\n",
    "\n",
    "        while queue:\n",
    "            x,y = queue.popleft()\n",
    "            if (x,y) in visited:\n",
    "                continue\n",
    "            visited.add((x,y))\n",
    "            cur_pos = x*n + y\n",
    "            dx = [0,0,1,-1]\n",
    "            dy = [1,-1,0,0]\n",
    "            for i in range(4):\n",
    "                nx,ny = x+dx[i],y+dy[i]\n",
    "                n_pos = nx*n + ny\n",
    "                new_dist = dist[cur_pos] + (0 if grid[x][y]==i+1 else 1)\n",
    "                if 0<=nx<m and 0<=ny<n and new_dist<dist[n_pos]:\n",
    "                    dist[n_pos] = new_dist\n",
    "                    if grid[x][y] == i+1:\n",
    "                        queue.appendleft((nx,ny))\n",
    "                    else:\n",
    "                        queue.append((nx,ny))\n",
    "            pass\n",
    "        return dist[m*n-1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "import heapq\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        m,n = len(grid),len(grid[0])\n",
    "        dist = [float('inf')]*(m*n)\n",
    "        dist[0] = 0\n",
    "        queue = [(0,0,0)]\n",
    "        seen = set()\n",
    "        while queue:\n",
    "            dis, x, y = heapq.heappop(queue)\n",
    "            if (x,y) in seen:\n",
    "                continue\n",
    "            seen.add((x,y))\n",
    "            # cur_pos = n*x+y\n",
    "            # if dist[cur_pos]<dis:\n",
    "            #     continue\n",
    "            dx = [0,0,1,-1]\n",
    "            dy = [1,-1,0,0]\n",
    "            for i in range(4):\n",
    "                nx, ny = x+dx[i], y+dy[i]\n",
    "                n_pos = nx*n+ny\n",
    "                if 0<=nx<m and 0<=ny<n:\n",
    "                    nextD = 0 if grid[x][y]==i+1 else 1\n",
    "                    if dis+nextD < dist[n_pos]:\n",
    "                        dist[n_pos] = dis+nextD\n",
    "                        heapq.heappush(queue, (dist[n_pos],nx,ny))\n",
    "        return dist[m*n-1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        m, n = len(grid), len(grid[0])\n",
    "        dp = [[float('inf') for _ in range(n)] for _ in range(m)]\n",
    "        q = []\n",
    "        heapq.heappush(q, (0, 0, 0))\n",
    "        dp[0][0] = 0\n",
    "        dirs = [(0, 1),(0, -1),(1, 0),(-1, 0)]\n",
    "        seen = set()\n",
    "        while q:\n",
    "            dist, x, y = heapq.heappop(q)\n",
    "            if (x, y) in seen:\n",
    "                continue\n",
    "            # if x == m - 1 and y == n - 1:\n",
    "            #     return dist\n",
    "            seen.add((x, y))\n",
    "            for i, di in enumerate(dirs):\n",
    "                curx, cury = di[0] + x, di[1] + y\n",
    "                temp = 0 if i + 1 == grid[x][y] else 1\n",
    "                ans = temp + dist\n",
    "                if 0 <= curx < m and 0 <= cury < n and ans < dp[curx][cury]:\n",
    "                    dp[curx][cury] = ans\n",
    "                    heappush(q, (ans, curx, cury))\n",
    "        return dp[-1][-1]\n",
    "                    \n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        m, n = len(grid), len(grid[0])\n",
    "        BIG = int(1e9)\n",
    "        dist = [0] + [BIG] * (m * n - 1)\n",
    "        seen = set()\n",
    "        q = [(0, 0, 0)]\n",
    "\n",
    "        while len(q) > 0:\n",
    "            cur_dis, x, y = heapq.heappop(q)\n",
    "            if (x, y) in seen:\n",
    "                continue\n",
    "            seen.add((x, y))\n",
    "            cur_pos = x * n + y\n",
    "            for i, (nx, ny) in enumerate([(x, y + 1), (x, y - 1), (x + 1, y), (x - 1, y)]):\n",
    "                new_pos = nx * n + ny\n",
    "                new_dis = dist[cur_pos] + (1 if grid[x][y] != i + 1 else 0)\n",
    "                if 0 <= nx < m and 0 <= ny < n and new_dis < dist[new_pos]:\n",
    "                    dist[new_pos] = new_dis\n",
    "                    heapq.heappush(q, (new_dis, nx, ny))\n",
    "        \n",
    "        return dist[m * n - 1]\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        m, n = len(grid), len(grid[0])\n",
    "        BIG = int(1e9)\n",
    "        dist = [0] + [BIG] * (m * n - 1)\n",
    "        seen = set()\n",
    "        q = collections.deque([(0, 0)])\n",
    "\n",
    "        while len(q) > 0:\n",
    "            x, y = q.popleft()\n",
    "            if (x, y) in seen:\n",
    "                continue\n",
    "            seen.add((x, y))\n",
    "            cur_pos = x * n + y\n",
    "            for i, (nx, ny) in enumerate([(x, y + 1), (x, y - 1), (x + 1, y), (x - 1, y)]):\n",
    "                new_pos = nx * n + ny\n",
    "                new_dis = dist[cur_pos] + (1 if grid[x][y] != i + 1 else 0)\n",
    "                if 0 <= nx < m and 0 <= ny < n and new_dis < dist[new_pos]:\n",
    "                    dist[new_pos] = new_dis\n",
    "                    if grid[x][y] == i + 1:\n",
    "                        q.appendleft((nx, ny))\n",
    "                    else:\n",
    "                        q.append((nx, ny))\n",
    "        \n",
    "        return dist[m * n - 1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        dir = [[-1, 0, 3], [1, 0, 4], [0, -1, 1], [0, 1, 2]]\n",
    "        r, c = len(grid), len(grid[0])\n",
    "        dq1 = deque([[r - 1, c - 1]])\n",
    "        dp = [[inf] * c for _ in range(r)]\n",
    "        dp[r - 1][c - 1] = 0\n",
    "        dq3, tmp = deque(), set()\n",
    "        cur = 0\n",
    "        while dq1:\n",
    "            dq2 = deque()\n",
    "            while dq1:\n",
    "                x, y = dq1.popleft()\n",
    "                for d1, d2, d in dir:\n",
    "                    u, v = x + d1, y + d2\n",
    "                    if 0 <= u < r and 0 <= v < c:\n",
    "                        if dp[u][v] != inf: continue\n",
    "                        if d == grid[u][v]:\n",
    "                            dp[u][v] = cur\n",
    "                            dq2.append([u, v])\n",
    "                        elif (u, v) not in tmp:\n",
    "                            dq3.append([u, v])\n",
    "                            tmp.add((u, v))\n",
    "            if dq2:\n",
    "                dq1 = dq2\n",
    "            else:\n",
    "                cur += 1\n",
    "                for (x, y) in tmp:\n",
    "                    dp[x][y] = cur\n",
    "                dq1, dq3, tmp = dq3, deque(), set()\n",
    "            if dp[0][0] != inf:\n",
    "                return dp[0][0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        m, n = len(grid), len(grid[0])\n",
    "        BIG = int(1e9)\n",
    "        dist = [0] + [BIG] * (m * n - 1)\n",
    "        seen = set()\n",
    "        q = [(0, 0, 0)]\n",
    "\n",
    "        while len(q) > 0:\n",
    "            cur_dis, x, y = heapq.heappop(q)\n",
    "            if (x, y) in seen or cur_dis>x+y:\n",
    "                continue\n",
    "            seen.add((x, y))\n",
    "            cur_pos = x * n + y\n",
    "            for i, (nx, ny) in enumerate([(x, y + 1), (x, y - 1), (x + 1, y), (x - 1, y)]):\n",
    "                new_pos = nx * n + ny\n",
    "                new_dis = dist[cur_pos] + (1 if grid[x][y] != i + 1 else 0)\n",
    "                if 0 <= nx < m and 0 <= ny < n and new_dis < dist[new_pos]:\n",
    "                    dist[new_pos] = new_dis\n",
    "                    heapq.heappush(q, (new_dis, nx, ny))\n",
    "        \n",
    "        return dist[m * n - 1]\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        m, n = len(grid), len(grid[0])\n",
    "        BIG = int(1e9)\n",
    "        dist = [0] + [BIG] * (m * n - 1)\n",
    "        seen = set()\n",
    "        q = [(0, 0, 0)]\n",
    "\n",
    "        while len(q) > 0:\n",
    "            cur_dis, x, y = heapq.heappop(q)\n",
    "            if (x, y) in seen or cur_dis>x+y:\n",
    "                continue\n",
    "            seen.add((x, y))\n",
    "            cur_pos = x * n + y\n",
    "            for i, (nx, ny) in enumerate([(x, y + 1), (x, y - 1), (x + 1, y), (x - 1, y)]):\n",
    "                new_pos = nx * n + ny\n",
    "                new_dis = dist[cur_pos] + (1 if grid[x][y] != i + 1 else 0)\n",
    "                if 0 <= nx < m and 0 <= ny < n and new_dis < dist[new_pos]:\n",
    "                    dist[new_pos] = new_dis\n",
    "                    heapq.heappush(q, (new_dis, nx, ny))\n",
    "        \n",
    "        return dist[m * n - 1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        dir = {1: (0, 1), 2: (0, -1), 3: (1, 0), 4: (-1, 0)} \n",
    "        m, n = len(grid), len(grid[0])\n",
    "        q1, q2 = deque(), deque()\n",
    "        vis = set()\n",
    "        q1.append((0, 0))\n",
    "        vis.add((0, 0))\n",
    "        dis = 0\n",
    "        while q1:\n",
    "            while q1:\n",
    "                x, y = q1.popleft()\n",
    "                q2.append((x, y))\n",
    "                if x == m - 1 and y == n - 1:\n",
    "                    return dis\n",
    "                nx, ny = x, y\n",
    "                while True:\n",
    "                    nx, ny = dir[grid[nx][ny]][0] + nx, dir[grid[nx][ny]][1] + ny\n",
    "                    # 下一个位置如果未遍历过，加入当前队列；否则退出\n",
    "                    if 0 <= nx < m and 0 <= ny < n and (nx, ny) not in vis:\n",
    "                        q1.append((nx, ny))\n",
    "                        vis.add((nx, ny))\n",
    "                    else:\n",
    "                        break\n",
    "            while q2:\n",
    "                x, y = q2.popleft()\n",
    "                for d in filter(lambda d: d != grid[x][y], range(1, 5)):\n",
    "                    nx, ny = dir[d][0] + x, dir[d][1] + y\n",
    "                    if 0 <= nx < m and 0 <= ny < n and (nx, ny) not in vis:\n",
    "                        q1.append((nx, ny))\n",
    "                        vis.add((nx, ny))\n",
    "            dis += 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        n,m = len(grid),len(grid[0])\n",
    "        dist = [0] + [float('inf')] * (m*n-1)\n",
    "        seen = set()\n",
    "        q = collections.deque([(0,0)])\n",
    "\n",
    "        while q:\n",
    "            x,y = q.popleft()\n",
    "            if (x,y) in seen:\n",
    "                continue\n",
    "            seen.add((x,y))\n",
    "            cur_pos = x * m + y\n",
    "            for i,(nx,ny) in enumerate([(x,y+1),(x,y-1),(x+1,y),(x-1,y)]):\n",
    "                new_pos = nx * m + ny\n",
    "                new_dis = dist[cur_pos] + (1 if grid[x][y] != i+1 else 0)\n",
    "                if 0 <= nx < n and 0 <= ny < m and new_dis < dist[new_pos]:\n",
    "                    dist[new_pos] = new_dis\n",
    "                    if grid[x][y] == i+1:\n",
    "                        q.appendleft((nx,ny))\n",
    "                    else:\n",
    "                        q.append((nx,ny))\n",
    "\n",
    "        print(dist)\n",
    "        return dist[-1]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "import heapq\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        m=len(grid)\n",
    "        n=len(grid[0])\n",
    "        maxv=int(1e9)\n",
    "        disv=[0]+[maxv]*(m*n-1)\n",
    "\n",
    "        find_set=set()\n",
    "        my_heapq=[[0,0,0]]\n",
    "\n",
    "        while my_heapq:\n",
    "            temp_dis,x,y=heapq.heappop(my_heapq)\n",
    "            if (x,y) in find_set:\n",
    "                continue\n",
    "\n",
    "            for index1,(nx,ny) in enumerate([(x,y+1),(x,y-1),(x+1,y),(x-1,y)]):\n",
    "                if 0<=nx<=m-1 and 0<=ny<=n-1:\n",
    "                    last_index=n*x+y\n",
    "                    last_dis=temp_dis\n",
    "                    addv=0\n",
    "                    if grid[x][y]!=index1+1:\n",
    "                        addv=1\n",
    "                    next_index=n*nx+ny\n",
    "                    if disv[next_index]>last_dis+addv:\n",
    "                        disv[next_index]=last_dis+addv\n",
    "                        heapq.heappush(my_heapq,[disv[next_index],nx,ny])\n",
    "\n",
    "            find_set.add((x,y))\n",
    "\n",
    "\n",
    "        return disv[m*n-1]\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "       \n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    # 按移动花费来 bfs 遍历图\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        m = len(grid)\n",
    "        n = len(grid[0])\n",
    "        # 移动方向数组，index+1 = 题目里的编号\n",
    "        dirs = [(0,1), (0,-1),(1,0),(-1,0)]\n",
    "        visited = set()\n",
    "        # 为了简单一点没有用队列，使用了dict+list，key 为 cost，value 为下标组成的list\n",
    "        # 表示从起始点到该list的中的点的花费为key值\n",
    "        costs = {0:[(0,0)]} \n",
    "        cost = 0\n",
    "        # 按 cost 遍历，由于遍历是 costs 中的 cost 会增多，不写成 for cost in costs\n",
    "        while cost in costs:\n",
    "            for i,j in costs[cost]:\n",
    "                # 目标点没有访问过\n",
    "                if (i,j) not in visited:\n",
    "                    visited.add((i,j))\n",
    "                    # 到达终点结束\n",
    "                    if i == m-1 and j == n-1:\n",
    "                        return cost\n",
    "                    # 求四个方向的消耗，并加入costs\n",
    "                    for val, d in enumerate(dirs):\n",
    "                        x = i + d[0]\n",
    "                        y = j + d[1]\n",
    "                        # 目标点合法，且没有访问过\n",
    "                        if 0<=x<m and 0<=j<n and (x,y) not in visited:\n",
    "                            # 如果和i，j的方向一致则cost不变，否则加1\n",
    "                            next_cost = cost + (0 if val+1 == grid[i][j] else 1)\n",
    "                            # 加入 costs\n",
    "                            if next_cost not in costs:\n",
    "                                costs[next_cost] = []\n",
    "                            costs[next_cost].append((x,y))\n",
    "            cost += 1\n",
    "        return 0\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        m, n = len(grid), len(grid[0])\n",
    "        vis = {(0, 0): 0}\n",
    "        best = set()\n",
    "        heap = [(0, 0, 0)]\n",
    "        while heap:\n",
    "            wei, i, j = heapq.heappop(heap)\n",
    "            if (i, j) == (m -1, n - 1):\n",
    "                return wei\n",
    "            best.add((i, j))          \n",
    "            for idx, p in enumerate(((i, j+1), (i, j-1), (i+1, j), (i-1, j))):\n",
    "                x, y = p\n",
    "                if 0 <= x < m and 0 <= y < n:\n",
    "                    w = wei + 1\n",
    "                    if grid[i][j] == idx + 1:\n",
    "                        w -= 1\n",
    "                    if ((x, y) not in vis) or ((x, y) not in best and w < vis[(x, y)]):\n",
    "                        vis[(x, y)] = w\n",
    "                        heapq.heappush(heap, (w, x, y))\n",
    "        \n",
    "            \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        vis = set()\n",
    "        m, n = len(grid), len(grid[0])\n",
    "        q = deque()\n",
    "        q.append((0, 0, 0))\n",
    "        dx, dy = [0, 0, 1, -1], [1, -1, 0, 0]\n",
    "        while q:\n",
    "            x, y, step = q.popleft()\n",
    "            if (x, y) in vis: continue\n",
    "            vis.add((x, y))\n",
    "            if x == m - 1 and y == n - 1: return step\n",
    "            for i in range(4):\n",
    "                nx, ny = x + dx[i], y + dy[i]\n",
    "                if 0 <= nx < m and 0 <= ny < n:\n",
    "                    if i + 1 == grid[x][y]:\n",
    "                        q.appendleft((nx, ny, step))\n",
    "                    else:\n",
    "                        q.append((nx, ny, step + 1))\n",
    "    \n",
    "        return 0      "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        vis = set()\n",
    "        m, n = len(grid), len(grid[0])\n",
    "        q = deque()\n",
    "        q.append((0, 0, 0))\n",
    "        vis.add((0, 0, 0))\n",
    "        dx, dy = [0, 0, 1, -1], [1, -1, 0, 0]\n",
    "        while q:\n",
    "            x, y, step = q.popleft()\n",
    "            if (x, y) in vis: continue\n",
    "            vis.add((x, y))\n",
    "            if x == m - 1 and y == n - 1: return step\n",
    "            for i in range(4):\n",
    "                nx, ny = x + dx[i], y + dy[i]\n",
    "                \n",
    "                if 0 <= nx < m and 0 <= ny < n:\n",
    "                    \n",
    "                    if i + 1 == grid[x][y]:\n",
    "                        q.appendleft((nx, ny, step))\n",
    "                    else:\n",
    "                        q.append((nx, ny, step + 1))\n",
    "    \n",
    "        return 0      "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        r, c = len(grid), len(grid[0])\n",
    "        queue = collections.deque([(0, 0, 0)])\n",
    "        seen = set()\n",
    "\n",
    "        mp = {1:(0,1),2:(0,-1),3:(1,0),4:(-1,0)}\n",
    "        while queue:\n",
    "            i, j, step = queue.popleft()\n",
    "\n",
    "            if i == r - 1 and j == c - 1:\n",
    "                return step\n",
    "            \n",
    "            if (i, j) in seen:\n",
    "                continue\n",
    "\n",
    "            seen.add((i, j))\n",
    "\n",
    "            for di, dj in [(1,0), (-1,0), (0,1),(0,-1)]:\n",
    "                newi, newj = i + di, j + dj\n",
    "\n",
    "                if 0<=newi<r and 0 <=newj<c:\n",
    "                    if mp[grid[i][j]] == (di, dj):\n",
    "                        queue.appendleft((newi, newj, step))\n",
    "                    else:\n",
    "                        queue.append((newi, newj, step + 1))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "\n",
    "        m, n = len(grid), len(grid[0])\n",
    "        q = deque([(0, 0, 0)])\n",
    "        dire = {(0, 1): 1, (0, -1): 2, (1, 0): 3, (-1, 0): 4}\n",
    "        dis = defaultdict(lambda: inf)\n",
    "        dis[(0, 0)] = 0\n",
    "        vis = set()\n",
    "        while q:\n",
    "            c, x, y = q.popleft()\n",
    "            if x == m - 1 and y == n - 1:\n",
    "                return c\n",
    "            if (x, y) in vis:\n",
    "                continue\n",
    "            vis.add((x, y))\n",
    "            for (dx, dy), val in dire.items():\n",
    "                nx, ny = x + dx, y + dy\n",
    "                if grid[x][y] == val:\n",
    "                    if 0 <= nx < m and 0 <= ny < n:\n",
    "                        if c < dis[(nx, ny)]:\n",
    "                            q.appendleft((c, nx, ny))\n",
    "                            dis[(nx, ny)] = c\n",
    "                else:\n",
    "                    if 0 <= nx < m and 0 <= ny < n:\n",
    "                        if c + 1 < dis[(nx, ny)]:\n",
    "                            q.append((c + 1, nx, ny))\n",
    "                            dis[(nx, ny)] = c + 1\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "\n",
    "        m, n = len(grid), len(grid[0])\n",
    "        q = [(0, 0, 0)]\n",
    "        dire = {(0, 1): 1, (0, -1): 2, (1, 0): 3, (-1, 0): 4}\n",
    "        dis = defaultdict(lambda: inf)\n",
    "        dis[(0, 0)] = 0\n",
    "        vis = set()\n",
    "        while q:\n",
    "            c, x, y = heapq.heappop(q)\n",
    "            if x == m - 1 and y == n - 1:\n",
    "                return c\n",
    "            if (x, y) in vis:\n",
    "                continue\n",
    "            vis.add((x, y))\n",
    "            for (dx, dy), val in dire.items():\n",
    "                nx, ny = x + dx, y + dy\n",
    "                if grid[x][y] == val:\n",
    "                    if 0 <= nx < m and 0 <= ny < n:\n",
    "                        if c < dis[(nx, ny)]:\n",
    "                            heapq.heappush(q, (c, nx, ny))\n",
    "                            dis[(nx, ny)] = c\n",
    "                else:\n",
    "                    if 0 <= nx < m and 0 <= ny < n:\n",
    "                        if c + 1 < dis[(nx, ny)]:\n",
    "                            heapq.heappush(q, (c + 1, nx, ny))\n",
    "                            dis[(nx, ny)] = c + 1\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        m, n = len(grid), len(grid[0])\n",
    "        dp = [[float('inf') for _ in range(n)] for _ in range(m)]\n",
    "        q = []\n",
    "        heapq.heappush(q, (0, 0, 0))\n",
    "        dirs = [(0, 1),(0, -1),(1, 0),(-1, 0)]\n",
    "        seen = set()\n",
    "        while q:\n",
    "            dist, x, y = heapq.heappop(q)\n",
    "            if (x, y) in seen:\n",
    "                continue\n",
    "            if x == m - 1 and y == n - 1:\n",
    "                return dist\n",
    "            seen.add((x, y))\n",
    "            for i, di in enumerate(dirs):\n",
    "                curx, cury = di[0] + x, di[1] + y\n",
    "                if 0 <= curx < m and 0 <= cury < n:\n",
    "                    \n",
    "                    if i + 1 == grid[x][y]:\n",
    "                        heappush(q, (dist, curx, cury))\n",
    "                    else:\n",
    "                        heappush(q, (dist + 1, curx, cury))\n",
    "                \n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        m, n = len(grid), len(grid[0])\n",
    "        heap = [[0, 0]]\n",
    "        visit = set()\n",
    "        while heap:\n",
    "            step, coor = heapq.heappop(heap) \n",
    "            i, j = coor // n, coor % n \n",
    "            if coor == m * n - 1:\n",
    "                return step \n",
    "            if coor in visit:\n",
    "                continue   \n",
    "            visit.add(coor)\n",
    "            for idx, d in enumerate([(0, 1), (0, -1), (1, 0), (-1, 0)]):\n",
    "                x = i + d[0]\n",
    "                y = j + d[1]\n",
    "                if 0 <= x < m and 0 <= y < n:\n",
    "                    heapq.heappush(heap, [step + (grid[i][j] != idx + 1), x * n + y])\n",
    "        return - 1\n",
    "        \n",
    "\n",
    "        m, n = len(grid), len(grid[0])\n",
    "        heap = [[0, 0]]\n",
    "        visit = set()\n",
    "        direction = [(0, 1), (0, - 1), (1, 0), (- 1, 0)]\n",
    "        while heap:\n",
    "            step, coor = heapq.heappop(heap)\n",
    "            if coor in visit:\n",
    "                continue \n",
    "            visit.add(coor)\n",
    "            if coor == m * n - 1:\n",
    "                return step \n",
    "            i, j = coor // n, coor % n \n",
    "            for idx in range(4):\n",
    "                x = i + direction[idx][0]\n",
    "                y = j + direction[idx][1]\n",
    "                if 0 <= x < m and 0 <= y < n:\n",
    "                    heapq.heappush(heap, [step + (grid[i][j] != idx + 1), x * n + y])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        m=len(grid);n=len(grid[0])\n",
    "        edge=[[] for i in range(m*n)]\n",
    "        f=[(0,0),(0,1),(0,-1),(1,0),(-1,0)]\n",
    "        for i in range(m):\n",
    "            for j in range(n):\n",
    "                for k in range(1,5):\n",
    "                    if(0<=i+f[k][0]<m and 0<=j+f[k][1]<n):\n",
    "                        edge[i*n+j].append(((i+f[k][0])*n+j+f[k][1],(grid[i][j]!=k)))\n",
    "        dis=[9999]*(n*m);dis[0]=0;pq=[(0,0)]\n",
    "        while(len(pq)):\n",
    "            x=heapq.heappop(pq)\n",
    "            if(x[0]!=dis[x[1]]):continue\n",
    "            if(x[1]==(n*m-1)):return x[0]\n",
    "            for i in edge[x[1]]:\n",
    "                if(dis[i[0]]>i[1]+x[0]):\n",
    "                    dis[i[0]]=i[1]+x[0]\n",
    "                    heapq.heappush(pq,(dis[i[0]],i[0]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        INF=0x3f3f3f3f\n",
    "        m=len(grid);n=len(grid[0])\n",
    "        ch=[[[] for _ in range(n+2)] for _ in range(m+2)]\n",
    "        for i in range(1,m+1):\n",
    "            for j in range(1,n+1):\n",
    "                ch[i][j]=[[i-1,j,1],[i+1,j,1],[i,j-1,1],[i,j+1,1]]\n",
    "                if grid[i-1][j-1]==1:\n",
    "                    ch[i][j][3][2]=0\n",
    "                elif grid[i-1][j-1]==2:\n",
    "                    ch[i][j][2][2]=0\n",
    "                elif grid[i-1][j-1]==3:\n",
    "                    ch[i][j][1][2]=0\n",
    "                else:\n",
    "                    ch[i][j][0][2]=0\n",
    "        dis=[[INF]*(n+2) for _ in range(m+2)]\n",
    "        vis=[[0]*(n+2) for _ in range(m+2)]\n",
    "        dis[1][1]=0\n",
    "        q=[(0,1,1)]\n",
    "        while q:\n",
    "            d,x,y=heappop(q)\n",
    "            if vis[x][y]: continue\n",
    "            vis[x][y]=1\n",
    "            for x1,y1,w in ch[x][y]:\n",
    "                if d+w<dis[x1][y1]:\n",
    "                    dis[x1][y1]=d+w\n",
    "                    heappush(q,(dis[x1][y1],x1,y1))\n",
    "        return dis[m][n]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "import collections\n",
    "\n",
    "class Solution:\n",
    "    def minCost(self, grid: List[List[int]]) -> int:\n",
    "        INF=0x3f3f3f3f\n",
    "        m=len(grid);n=len(grid[0])\n",
    "        ch=[[[] for _ in range(n+2)] for _ in range(m+2)]\n",
    "        for i in range(1,m+1):\n",
    "            for j in range(1,n+1):\n",
    "                ch[i][j]=[[i-1,j,1],[i+1,j,1],[i,j-1,1],[i,j+1,1]]\n",
    "                if grid[i-1][j-1]==1:\n",
    "                    ch[i][j][3][2]=0\n",
    "                elif grid[i-1][j-1]==2:\n",
    "                    ch[i][j][2][2]=0\n",
    "                elif grid[i-1][j-1]==3:\n",
    "                    ch[i][j][1][2]=0\n",
    "                else:\n",
    "                    ch[i][j][0][2]=0\n",
    "        dis=[[INF]*(n+2) for _ in range(m+2)]\n",
    "        vis=[[0]*(n+2) for _ in range(m+2)]\n",
    "        dis[1][1]=0\n",
    "        q=[(0,1,1)]\n",
    "        while q:\n",
    "            d,x,y=heappop(q)\n",
    "            if vis[x][y]: continue\n",
    "            vis[x][y]=1\n",
    "            for x1,y1,w in ch[x][y]:\n",
    "                if d+w<dis[x1][y1]:\n",
    "                    dis[x1][y1]=d+w\n",
    "                    heappush(q,(dis[x1][y1],x1,y1))\n",
    "        return dis[m][n]"
   ]
  }
 ],
 "metadata": {},
 "nbformat": 4,
 "nbformat_minor": 2
}
